From 4ee8cf7c968c5f073df9548b553490ec57ac2e9e Mon Sep 17 00:00:00 2001
From: Tessa Thornton
Date: Tue, 26 Nov 2019 11:26:53 -0500
Subject: [PATCH] new admin branding (#2692)
* add comment revisions
* add strings
* update fixtures
* fix fixtures
* [CORL-629] Update admin moderation containers to use new branding tokens (#2600)
* Convert the moderation card components to use new styles
CORL-629
* Style the details area in the moderate card using new font and color styles
CORL-629
* Update FlagDetails on Moderate Card to match new branding styles
CORL-629
* Remove typography from ModerateCard Username
CORL-629
* Remove unnecessary new typography tokens created while experimenting
CORL-629
* Update background colors of username buttons on moderate card
CORL-629
* Update approve reject buttons to use new colors
CORL-629
* Fix alignment of username and "Reply to" in InReplyTo component
CORL-629
* Update moderated by on moderate card to match new branding
CORL-629
* Create distinct admin marker and counter components with new branding styles
Update moderate card components to use these distinct newly branded styles.
CORL-629
* Create independent Tabs control with new styling for admin area
Use it on the moderate card details area.
CORL-629
* Remove letter spacing from moderate card styles
CORL-629
* Update "DETAILS" tab on moderate card to be named "INFO"
CORL-629
* Update some missing v2 css variables
CORL-629
* Tweak the spacing of the COMMENT link and title on the moderate card
CORL-629
* Update details font color on moderate card
CORL-629
* Update spacing on newly styled Admin Tab component
CORL-629
* Update spacing of reply to username on the moderate card
CORL-629
* Update moderate card comment text area minimum width and height
CORL-629
* Update vertical divider on moderate card to updated branding
CORL-629
* Introduce new bold open sans font face
Downgrades all existing bold's to semi-bold as they were equivalent before.
CORL-629
* Update moderate card details tabs to use new bold open sans font
CORL-629
* Create an admin specific timestamp control that implements new branding
CORL-629
* Migrate shared moderate card styles into child component files
CORL-629
* [CORL-631] Update admin side main navigation to new branding styles (#2625)
* Convert the moderation card components to use new styles
CORL-629
* Style the details area in the moderate card using new font and color styles
CORL-629
* Update FlagDetails on Moderate Card to match new branding styles
CORL-629
* Remove typography from ModerateCard Username
CORL-629
* Remove unnecessary new typography tokens created while experimenting
CORL-629
* Update background colors of username buttons on moderate card
CORL-629
* Update approve reject buttons to use new colors
CORL-629
* Fix alignment of username and "Reply to" in InReplyTo component
CORL-629
* Update moderated by on moderate card to match new branding
CORL-629
* Create distinct admin marker and counter components with new branding styles
Update moderate card components to use these distinct newly branded styles.
CORL-629
* Create independent Tabs control with new styling for admin area
Use it on the moderate card details area.
CORL-629
* Remove letter spacing from moderate card styles
CORL-629
* Update "DETAILS" tab on moderate card to be named "INFO"
CORL-629
* Update some missing v2 css variables
CORL-629
* Tweak the spacing of the COMMENT link and title on the moderate card
CORL-629
* Update details font color on moderate card
CORL-629
* Update spacing on newly styled Admin Tab component
CORL-629
* Update spacing of reply to username on the moderate card
CORL-629
* Update moderate card comment text area minimum width and height
CORL-629
* Update vertical divider on moderate card to updated branding
CORL-629
* Introduce new bold open sans font face
Downgrades all existing bold's to semi-bold as they were equivalent before.
CORL-629
* Update moderate card details tabs to use new bold open sans font
CORL-629
* Create an admin specific timestamp control that implements new branding
CORL-629
* Migrate shared moderate card styles into child component files
CORL-629
* Update main navigation admin side to use new branding styles
CORL-631
* Bring in some preliminary color and font styles for the search bar
This helps it match navigation, but does not update all the sub-styles of
the search bar's many child components.
CORL-631
* [CORL-694] use new styles for decision history (#2644)
* use new styles for decision history
* remove reference to nonexistent variable
* update snaps
* [CORL 695] admin branding - user menu (#2650)
* update user menu, popover, and dropdown to new design tokens
* fix feature button colours
* use v2 spacing vars
* admin branding: tables (#2651)
* update user menu, popover, and dropdown to new design tokens
* fix feature button colours
* use v2 spacing vars
* style stories and users table
* update snap
* update user status font weight
* remove duplicate declaration
* fix line height references
* update design tokens for text inputs and selects (#2658)
* use box shadow instead of outline for focus states
* Update snapshots to adjust for resolved merge conflicts
* Bring new branding styles to button components (#2667)
* Create preliminary filled and outline buttons that match branding
* Add adornment button variant to newly branded button
* Add the ghost variant to the newly branded button component
* Add underlined variant to the newly branded button component
* Remove external Icon composes property
* Convert camel-case button variables to kebab-case
* [CORL-672] Configuration pages new branding (#2673)
* style config side nav
* general configuration tab branding
* organization tab branding
* moderation configuration branding
* banned/suspect words config branding
* email config branding
* advanced settings branding
* auth config branding
* move helpertext and fieldset components
* add textarea component
* add back gutters on table search
* update snaps
* fix header component to accept labels
* use new spacing form components
* use spacing components for advanced config
* fix tests
* fix line height of radio buttons
* update validation message branding
* update snaps
* fix paths casing
* try lowercase then
* add docs for new form components
* move description component
* update snaps
* move components to /ui/v2
* [CORL-673] Update the moderate area search menu to use new branding styles (#2672)
* Create preliminary filled and outline buttons that match branding
* Add adornment button variant to newly branded button
* Add the ghost variant to the newly branded button component
* Add underlined variant to the newly branded button component
* Remove external Icon composes property
* Convert camel-case button variables to kebab-case
* Preliminarily migrate raw components into v2 to prep for branding updates
CORL-673
* Preliminarily update the search results bar to use new branding tokens
CORL-673
* Update styles to new branding on migrated v2 client-ui components
CORL-673
* Update see all and moderate all search option icons
CORL-673
* style config side nav
* general configuration tab branding
* organization tab branding
* moderation configuration branding
* banned/suspect words config branding
* email config branding
* advanced settings branding
* auth config branding
* move helpertext and fieldset components
* add textarea component
* add back gutters on table search
* update snaps
* fix header component to accept labels
* use new spacing form components
* use spacing components for advanced config
* fix tests
* fix line height of radio buttons
* update validation message branding
* update snaps
* fix paths casing
* try lowercase then
* add docs for new form components
* move description component
* update snaps
* move components to /ui/v2
* Set size="md" on the Icon component and not the Localized component
CORL-673
* tag component
* [CORL-669] user drawer + misc branding (#2686)
* tag component
* top of user drawer branding
* recent history in drawer
* add tooltips component
* use correct spacing prop
* history tabs
* user history and rejected comments
* move callout component'
* moderator notes components
* account history table
* table user row
* swap in tabs components
* remove overflow:hidden on buttons
* update snaps
* replace overflow scroll with auto
* clean up from rebasing vs master
* fix ts
* sort exports
* fix confusing linting errors
* update snaps
* clean up nav bar design
* adjust nav hover colors
* comment content component
* update nav hover styles
* fix search bar border
* clean up moderate card components
* more user drawer cleanup
* user role switcher
* update textfield vars and variants
* update components in community page
* move clickoutside component
* clean up stories table
* moderate route components
* single moderate view
* queue components
* delay component
* relative time component
* decision history components
* user drawer components cleanup
* configure components
* clean up buttons
* update snaps
* add all exports
* [CORL-674] admin branding: modals (#2695)
* update hotkeys modal components
* hotkeys modal
* user status change modals
* user status change modals
* invite users modal
* fix tests
* fix incorrect i18n string
* resolve merge conflicts
* move fonts to devdeps
* Fix username props interface
* fix dom nesting in components
* update formatting in strings
* rewrite delay component as functional component
* remove tslint comments
* change configure header component props
---
package-lock.json | 12 +
package.json | 2 +
.../App/DecisionHistory/ApprovedComment.tsx | 11 +-
.../App/DecisionHistory/ApprovedIcon.css | 2 +-
.../App/DecisionHistory/ApprovedIcon.tsx | 6 +-
.../DecisionHistory/DecisionHistoryButton.css | 4 +-
.../DecisionHistory/DecisionHistoryButton.tsx | 7 +-
.../DecisionHistoryLoading.tsx | 2 +-
.../App/DecisionHistory/DecisionItem.css | 5 +-
.../App/DecisionHistory/DecisionItem.tsx | 2 +-
.../App/DecisionHistory/DecisionList.css | 2 +-
.../admin/App/DecisionHistory/DotDivider.css | 8 +-
.../admin/App/DecisionHistory/Empty.css | 7 +
.../admin/App/DecisionHistory/Empty.tsx | 6 +-
.../admin/App/DecisionHistory/Footer.css | 1 +
.../admin/App/DecisionHistory/Footer.tsx | 2 +-
.../App/DecisionHistory/GoToCommentLink.css | 13 +-
.../App/DecisionHistory/GoToCommentLink.tsx | 2 +-
.../client/admin/App/DecisionHistory/Info.css | 7 +-
.../client/admin/App/DecisionHistory/Info.tsx | 4 +-
.../App/DecisionHistory/RejectedComment.tsx | 11 +-
.../App/DecisionHistory/RejectedIcon.css | 2 +-
.../App/DecisionHistory/RejectedIcon.tsx | 6 +-
.../App/DecisionHistory/ShowMoreButton.css | 17 +-
.../App/DecisionHistory/ShowMoreButton.tsx | 2 +-
.../admin/App/DecisionHistory/Timestamp.css | 11 +-
.../admin/App/DecisionHistory/Timestamp.tsx | 2 +-
.../admin/App/DecisionHistory/Title.css | 24 +-
.../admin/App/DecisionHistory/Title.tsx | 10 +-
.../admin/App/DecisionHistory/Username.css | 7 +
.../admin/App/DecisionHistory/Username.tsx | 13 +
.../ApprovedComment.spec.tsx.snap | 10 +-
.../__snapshots__/ApprovedIcon.spec.tsx.snap | 3 +-
.../__snapshots__/Empty.spec.tsx.snap | 6 +-
.../__snapshots__/Info.spec.tsx.snap | 4 +-
.../RejectedComment.spec.tsx.snap | 10 +-
.../__snapshots__/RejectedIcon.spec.tsx.snap | 1 +
.../__snapshots__/Title.spec.tsx.snap | 11 +-
src/core/client/admin/App/Main.tsx | 2 +-
.../admin/App/Navigation/Navigation.tsx | 2 +-
.../admin/App/Navigation/NavigationLink.tsx | 2 +-
.../client/admin/App/UserMenu/UserMenu.css | 12 +-
.../client/admin/App/UserMenu/UserMenu.tsx | 11 +-
.../client/admin/components/AutoLoadMore.tsx | 2 +-
.../components/ModerateCard/ApproveButton.css | 16 +-
.../components/ModerateCard/ApproveButton.tsx | 2 +-
.../ModerateCard/BanCommentUserMutation.ts | 3 +-
.../ModerateCard/CommentAuthorContainer.tsx | 5 +-
.../ModerateCard/CommentContent.css | 47 +-
.../ModerateCard/CommentContent.tsx | 4 +-
.../ModerateCard/CommentRevisionContainer.tsx | 2 +-
.../components/ModerateCard/FeatureButton.css | 27 +-
.../components/ModerateCard/FeatureButton.tsx | 2 +-
.../ModerateCard/FlagDetailsCategory.css | 6 +-
.../ModerateCard/FlagDetailsCategory.tsx | 6 +-
.../ModerateCard/FlagDetailsContainer.tsx | 2 +-
.../ModerateCard/FlagDetailsEntry.css | 40 +-
.../ModerateCard/FlagDetailsEntry.tsx | 2 +-
.../components/ModerateCard/InReplyTo.css | 32 +-
.../ModerateCard/InReplyTo.spec.tsx | 3 +
.../components/ModerateCard/InReplyTo.tsx | 22 +-
.../admin/components/ModerateCard/Markers.css | 17 +-
.../admin/components/ModerateCard/Markers.tsx | 6 +-
.../ModerateCard/MarkersContainer.tsx | 24 +-
.../components/ModerateCard/ModerateCard.css | 155 +-
.../components/ModerateCard/ModerateCard.tsx | 106 +-
.../ModerateCard/ModerateCardContainer.tsx | 3 +-
.../ModerateCardDetailsContainer.css | 6 +-
.../ModerateCardDetailsContainer.tsx | 25 +-
.../ModerateCard/ModeratedByContainer.css | 25 +-
.../ModerateCard/ModeratedByContainer.tsx | 2 +-
.../components/ModerateCard/RejectButton.css | 14 +-
.../components/ModerateCard/RejectButton.tsx | 2 +-
.../components/ModerateCard/ToxicityLabel.css | 10 +-
.../components/ModerateCard/ToxicityLabel.tsx | 17 +-
.../components/ModerateCard/Username.css | 7 +-
.../components/ModerateCard/Username.tsx | 10 +-
.../CommentContent.spec.tsx.snap | 6 +-
.../__snapshots__/InReplyTo.spec.tsx.snap | 9 +-
.../MarkersContainer.spec.tsx.snap | 46 +-
.../__snapshots__/ModerateCard.spec.tsx.snap | 576 ++---
.../__snapshots__/Username.spec.tsx.snap | 2 +-
.../client/admin/components/NotAvailable.css | 2 +-
.../CreateModeratorNoteMutation.ts | 3 +-
.../DeleteModeratorNoteMutation.ts | 3 +-
.../UserHistoryDrawer/ModeratorNote.css | 46 +-
.../UserHistoryDrawer/ModeratorNote.tsx | 29 +-
.../UserHistoryDrawer/RecentHistory.css | 38 +-
.../UserHistoryDrawer/RecentHistory.tsx | 70 +-
.../components/UserHistoryDrawer/Tabs.css | 25 +-
.../components/UserHistoryDrawer/Tabs.tsx | 24 +-
.../UserHistoryDrawer/UserBadgesContainer.tsx | 2 +-
.../UserDrawerAccountHistory.tsx | 2 +-
.../UserDrawerAccountHistoryQuery.css | 4 +-
.../UserDrawerAccountHistoryQuery.tsx | 2 +-
.../UserDrawerNotesContainer.css | 21 +-
.../UserDrawerNotesContainer.tsx | 40 +-
.../UserDrawerNotesQuery.tsx | 6 +-
.../UserHistoryDrawer/UserHistoryDrawer.css | 4 +-
.../UserHistoryDrawer/UserHistoryDrawer.tsx | 3 +-
.../UserHistoryDrawerAllComments.tsx | 10 +-
.../UserHistoryDrawerAllCommentsQuery.tsx | 2 +-
.../UserHistoryDrawerContainer.css | 79 +-
.../UserHistoryDrawerContainer.tsx | 161 +-
.../UserHistoryDrawerQuery.tsx | 2 +-
.../UserHistoryDrawerRejectedComments.tsx | 8 +-
...UserHistoryDrawerRejectedCommentsQuery.tsx | 2 +-
.../UserStatusDetailsContainer.css | 14 +
.../UserStatusDetailsContainer.tsx | 25 +-
.../components/UserRole/UserRoleChange.tsx | 6 +-
.../components/UserRole/UserRoleText.css | 9 +-
.../admin/components/UserStatus/BanModal.css | 13 +-
.../admin/components/UserStatus/BanModal.tsx | 113 +-
.../UserStatus/ChangeStatusModal.css | 5 +
.../UserStatus/ChangeStatusModal.tsx | 51 +
.../UserStatus/ChangeStatusModalHeader.css | 10 +
.../UserStatus/ChangeStatusModalHeader.tsx | 15 +
.../UserStatus/ModalHeaderUsername.css | 8 +
.../UserStatus/ModalHeaderUsername.tsx | 9 +
.../components/UserStatus/PremodModal.css | 12 +-
.../components/UserStatus/PremodModal.tsx | 102 +-
.../components/UserStatus/SuspendForm.css | 12 +
.../components/UserStatus/SuspendForm.tsx | 132 +-
.../components/UserStatus/SuspendModal.css | 23 +-
.../components/UserStatus/SuspendModal.tsx | 147 +-
.../components/UserStatus/UserStatus.css | 20 +
.../components/UserStatus/UserStatus.tsx | 27 +-
.../UserStatus/UserStatusChange.css | 9 +-
.../UserStatus/UserStatusChange.tsx | 14 +-
.../UserStatus/UserStatusChangeContainer.tsx | 11 +-
.../admin/routes/Community/EmptyMessage.css | 6 +-
.../admin/routes/Community/EmptyMessage.tsx | 6 +-
.../Community/InviteUsers/EmailField.tsx | 15 +-
.../Community/InviteUsers/InviteUsers.css | 3 +
.../Community/InviteUsers/InviteUsers.tsx | 7 +-
.../Community/InviteUsers/InviteUsersForm.css | 9 +
.../Community/InviteUsers/InviteUsersForm.tsx | 21 +-
.../InviteUsers/InviteUsersModal.css | 13 +
.../InviteUsers/InviteUsersModal.tsx | 19 +-
.../Community/InviteUsers/RoleField.css | 9 +
.../Community/InviteUsers/RoleField.tsx | 8 +-
.../routes/Community/InviteUsers/Success.css | 10 +
.../routes/Community/InviteUsers/Success.tsx | 6 +-
.../client/admin/routes/Community/UserRow.css | 11 +-
.../client/admin/routes/Community/UserRow.tsx | 9 +-
.../admin/routes/Community/UserTable.css | 4 +-
.../admin/routes/Community/UserTable.tsx | 6 +-
.../routes/Community/UserTableContainer.tsx | 2 +-
.../routes/Community/UserTableFilter.css | 6 -
.../routes/Community/UserTableFilter.tsx | 281 ++-
.../admin/routes/Configure/ConfigBox.css | 16 +-
.../admin/routes/Configure/ConfigBox.tsx | 33 +-
.../admin/routes/Configure/Configure.tsx | 3 +-
.../routes/Configure/Fields/LocaleField.tsx | 25 +
.../client/admin/routes/Configure/Header.css | 15 +-
.../client/admin/routes/Configure/Header.tsx | 46 +-
.../admin/routes/Configure/HelperText.css | 7 +
.../admin/routes/Configure/HelperText.tsx | 14 +
.../admin/routes/Configure/HorizontalRule.css | 2 +-
.../client/admin/routes/Configure/Layout.tsx | 2 +-
.../client/admin/routes/Configure/Link.css | 36 +-
.../admin/routes/Configure/OnOffField.tsx | 2 +-
.../routes/Configure/PermissionField.tsx | 2 +-
.../admin/routes/Configure/SectionContent.css | 4 +-
.../admin/routes/Configure/SectionContent.tsx | 4 +-
.../admin/routes/Configure/Subheader.css | 11 +-
.../admin/routes/Configure/Subheader.tsx | 6 +-
.../Configure/TextFieldWithValidation.css | 2 +
.../Configure/TextFieldWithValidation.tsx | 25 +
.../routes/Configure/ValidationMessage.tsx | 21 +-
.../__snapshots__/ConfigBox.spec.tsx.snap | 12 +-
.../__snapshots__/Header.spec.tsx.snap | 5 +-
.../__snapshots__/Subheader.spec.tsx.snap | 5 +-
.../sections/Advanced/AdvancedConfig.tsx | 2 +-
.../sections/Advanced/AdvancedConfigRoute.tsx | 2 +-
.../Advanced/CommentStreamLiveUpdates.tsx | 39 +-
.../sections/Advanced/CustomCSSConfig.tsx | 87 +-
.../Configure/sections/Advanced/EmbedCode.css | 3 +-
.../Configure/sections/Advanced/EmbedCode.tsx | 53 +-
.../Advanced/PermittedDomainsConfig.tsx | 99 +-
.../sections/Advanced/StoryCreationConfig.tsx | 166 +-
.../sections/Auth/AccountFeaturesConfig.tsx | 235 +-
.../Configure/sections/Auth/AuthConfig.tsx | 2 +-
.../sections/Auth/AuthConfigContainer.tsx | 2 +-
.../sections/Auth/AuthConfigRoute.tsx | 2 +-
.../sections/Auth/AuthIntegrationsConfig.tsx | 2 +-
.../Configure/sections/Auth/ClientIDField.tsx | 31 +-
.../sections/Auth/ClientSecretField.tsx | 6 +-
.../Auth/ConfigBoxWithToggleField.tsx | 2 +-
.../sections/Auth/ConfigDescription.tsx | 22 -
.../sections/Auth/FacebookConfig.tsx | 15 +-
.../Configure/sections/Auth/GoogleConfig.tsx | 14 +-
.../sections/Auth/LocalAuthConfig.tsx | 9 +-
.../Configure/sections/Auth/OIDCConfig.tsx | 177 +-
.../Configure/sections/Auth/RedirectField.tsx | 6 +-
.../sections/Auth/RegistrationField.tsx | 26 +-
.../Configure/sections/Auth/SSOConfig.tsx | 8 +-
.../Configure/sections/Auth/SSOKeyField.tsx | 18 +-
.../Configure/sections/Auth/SessionConfig.tsx | 32 +-
.../sections/Auth/TargetFilterField.tsx | 4 +-
.../sections/Email/EmailConfigContainer.css | 1 +
.../sections/Email/EmailConfigContainer.tsx | 82 +-
.../sections/Email/EmailConfigRoute.tsx | 2 +-
.../routes/Configure/sections/Email/From.tsx | 88 +-
.../routes/Configure/sections/Email/SMTP.tsx | 104 +-
.../General/ClosedStreamMessageConfig.tsx | 68 +-
.../General/ClosingCommentStreamsConfig.tsx | 112 +-
.../sections/General/CommentEditingConfig.tsx | 101 +-
.../sections/General/CommentLengthConfig.css | 8 +
.../sections/General/CommentLengthConfig.tsx | 231 +-
.../sections/General/GeneralConfig.tsx | 2 +-
.../sections/General/GeneralConfigRoute.tsx | 2 +-
.../sections/General/GuidelinesConfig.tsx | 54 +-
.../General/LocaleConfigContainer.tsx | 58 +-
.../sections/General/ReactionConfig.css | 2 +-
.../sections/General/ReactionConfig.tsx | 280 ++-
.../General/SitewideCommentingConfig.tsx | 99 +-
.../sections/General/StaffConfig.tsx | 102 +-
.../sections/General/StaffConfigContainer.tsx | 3 +-
.../sections/Moderation/APIKeyField.tsx | 7 +-
.../sections/Moderation/AkismetConfig.tsx | 160 +-
.../sections/Moderation/ModerationConfig.tsx | 2 +-
.../Moderation/ModerationConfigRoute.tsx | 2 +-
.../sections/Moderation/PerspectiveConfig.tsx | 322 ++-
.../Moderation/PreModerationConfig.tsx | 75 +-
.../Moderation/RecentCommentHistoryConfig.tsx | 166 +-
.../Organization/OrganizationConfig.tsx | 2 +-
.../Organization/OrganizationConfigRoute.tsx | 2 +-
.../OrganizationContactEmailConfig.tsx | 85 +-
.../Organization/OrganizationNameConfig.tsx | 75 +-
.../Organization/OrganizationURLConfig.tsx | 75 +-
.../WordList/BannedWordListConfig.tsx | 65 +-
.../WordList/SuspectWordListConfig.tsx | 70 +-
.../sections/WordList/WordListConfig.tsx | 2 +-
.../sections/WordList/WordListConfigRoute.tsx | 2 +-
.../sections/WordList/WordListTextArea.css | 1 -
.../sections/WordList/WordListTextArea.tsx | 3 +-
.../admin/routes/Moderate/HotkeysModal.css | 45 +-
.../admin/routes/Moderate/HotkeysModal.tsx | 67 +-
.../client/admin/routes/Moderate/Moderate.css | 4 +-
.../client/admin/routes/Moderate/Moderate.tsx | 2 +-
.../routes/Moderate/ModerateContainer.tsx | 2 +-
.../ModerateNavigation/Navigation.tsx | 2 +-
.../ModerateNavigation/NavigationLink.tsx | 2 +-
.../routes/Moderate/ModerateSearchBar/Bar.css | 9 +-
.../routes/Moderate/ModerateSearchBar/Bar.tsx | 10 +-
.../Moderate/ModerateSearchBar/Field.css | 53 +-
.../Moderate/ModerateSearchBar/Field.tsx | 6 +-
.../ModerateSearchBar/GoToAriaInfo.tsx | 2 +-
.../Moderate/ModerateSearchBar/Group.css | 18 +-
.../ModerateSearchBar/ModerateAllOption.css | 14 +-
.../ModerateSearchBar/ModerateAllOption.tsx | 10 +-
.../ModerateSearchBarContainer.tsx | 2 +-
.../Moderate/ModerateSearchBar/Option.css | 28 +-
.../ModerateSearchBar/SeeAllOption.css | 19 +-
.../ModerateSearchBar/SeeAllOption.tsx | 6 +-
.../Moderate/ModerateSearchBar/variables.css | 25 +
.../routes/Moderate/Queue/EmptyMessage.css | 6 +-
.../routes/Moderate/Queue/EmptyMessage.tsx | 2 +-
.../routes/Moderate/Queue/LoadingQueue.tsx | 2 +-
.../admin/routes/Moderate/Queue/Queue.tsx | 3 +-
.../SingleModerate/SingleModerate.css | 33 +-
.../SingleModerate/SingleModerate.tsx | 2 +-
src/core/client/admin/routes/NotFound.css | 6 +
src/core/client/admin/routes/NotFound.tsx | 6 +-
.../admin/routes/Stories/EmptyMessage.css | 6 +-
.../admin/routes/Stories/EmptyMessage.tsx | 6 +-
.../admin/routes/Stories/NoMatchMessage.css | 6 +-
.../admin/routes/Stories/NoMatchMessage.tsx | 6 +-
.../client/admin/routes/Stories/StoryRow.css | 1 -
.../client/admin/routes/Stories/StoryRow.tsx | 2 +-
.../Stories/StoryStatus/StoryStatusChange.tsx | 6 +-
.../Stories/StoryStatus/StoryStatusText.css | 8 +-
.../admin/routes/Stories/StoryTable.css | 4 +-
.../admin/routes/Stories/StoryTable.tsx | 4 +-
.../routes/Stories/StoryTableContainer.tsx | 2 +-
.../admin/routes/Stories/StoryTableFilter.css | 6 -
.../admin/routes/Stories/StoryTableFilter.tsx | 168 +-
.../__snapshots__/community.spec.tsx.snap | 684 +++---
.../__snapshots__/advanced.spec.tsx.snap | 553 +++--
.../__snapshots__/auth.spec.tsx.snap | 2051 +++++++++--------
.../__snapshots__/general.spec.tsx.snap | 1763 +++++++-------
.../__snapshots__/moderation.spec.tsx.snap | 1454 ++++++------
.../__snapshots__/organization.spec.tsx.snap | 199 +-
.../__snapshots__/wordList.spec.tsx.snap | 140 +-
.../decisionHistory.spec.tsx.snap | 167 +-
.../__snapshots__/regularQueue.spec.tsx.snap | 725 +++---
.../__snapshots__/rejectedQueue.spec.tsx.snap | 414 ++--
.../__snapshots__/searchBar.spec.tsx.snap | 6 +-
.../__snapshots__/singleComment.spec.tsx.snap | 204 +-
.../__snapshots__/stories.spec.tsx.snap | 352 +--
src/core/client/admin/ui/components/index.ts | 0
.../framework/components/CopyButton.tsx | 7 +-
.../stream/tabs/Configure/Configure.tsx | 2 +-
.../client/ui/components/Dropdown/Button.css | 8 +-
.../client/ui/components/Marker/Marker.css | 1 +
.../ui/components/Typography/Typography.css | 8 +-
.../ui/components/Typography/Typography.tsx | 10 +-
.../client/ui/components/v2/AppBar/AppBar.css | 18 +
.../client/ui/components/v2/AppBar/AppBar.mdx | 37 +
.../ui/components/v2/AppBar/AppBar.spec.tsx | 18 +
.../client/ui/components/v2/AppBar/AppBar.tsx | 38 +
.../client/ui/components/v2/AppBar/Begin.css | 3 +
.../ui/components/v2/AppBar/Begin.spec.tsx | 17 +
.../client/ui/components/v2/AppBar/Begin.tsx | 27 +
.../ui/components/v2/AppBar/Divider.css | 4 +
.../ui/components/v2/AppBar/Divider.spec.tsx | 10 +
.../ui/components/v2/AppBar/Divider.tsx | 17 +
.../client/ui/components/v2/AppBar/End.css | 4 +
.../ui/components/v2/AppBar/End.spec.tsx | 17 +
.../client/ui/components/v2/AppBar/End.tsx | 27 +
.../ui/components/v2/AppBar/Navigation.css | 11 +
.../components/v2/AppBar/Navigation.spec.tsx | 15 +
.../ui/components/v2/AppBar/Navigation.tsx | 24 +
.../components/v2/AppBar/NavigationItem.css | 45 +
.../v2/AppBar/NavigationItem.spec.tsx | 20 +
.../components/v2/AppBar/NavigationItem.tsx | 41 +
.../AppBar/__snapshots__/AppBar.spec.tsx.snap | 19 +
.../AppBar/__snapshots__/Begin.spec.tsx.snap | 15 +
.../__snapshots__/Divider.spec.tsx.snap | 11 +
.../v2/AppBar/__snapshots__/End.spec.tsx.snap | 15 +
.../__snapshots__/Navigation.spec.tsx.snap | 14 +
.../NavigationItem.spec.tsx.snap | 19 +
.../client/ui/components/v2/AppBar/index.ts | 6 +
.../ui/components/v2/AriaInfo/AriaInfo.css | 10 +
.../ui/components/v2/AriaInfo/AriaInfo.mdx | 18 +
.../components/v2/AriaInfo/AriaInfo.spec.tsx | 14 +
.../ui/components/v2/AriaInfo/AriaInfo.tsx | 36 +
.../__snapshots__/AriaInfo.spec.tsx.snap | 9 +
.../client/ui/components/v2/AriaInfo/index.ts | 1 +
.../ui/components/v2/Backdrop/Backdrop.css | 15 +
.../ui/components/v2/Backdrop/Backdrop.mdx | 32 +
.../components/v2/Backdrop/Backdrop.spec.tsx | 16 +
.../ui/components/v2/Backdrop/Backdrop.tsx | 35 +
.../__snapshots__/Backdrop.spec.tsx.snap | 24 +
.../client/ui/components/v2/Backdrop/index.ts | 1 +
.../components/v2/BaseButton/BaseButton.css | 43 +
.../components/v2/BaseButton/BaseButton.mdx | 28 +
.../v2/BaseButton/BaseButton.spec.tsx | 24 +
.../components/v2/BaseButton/BaseButton.tsx | 99 +
.../__snapshots__/BaseButton.spec.tsx.snap | 29 +
.../ui/components/v2/BaseButton/index.ts | 1 +
src/core/client/ui/components/v2/Box/Box.css | 240 ++
src/core/client/ui/components/v2/Box/Box.mdx | 30 +
src/core/client/ui/components/v2/Box/Box.tsx | 164 ++
src/core/client/ui/components/v2/Box/index.ts | 1 +
.../client/ui/components/v2/Button/Button.css | 508 ++++
.../client/ui/components/v2/Button/Button.mdx | 206 ++
.../ui/components/v2/Button/Button.spec.tsx | 62 +
.../client/ui/components/v2/Button/Button.tsx | 118 +
.../ui/components/v2/Button/ButtonIcon.css | 8 +
.../components/v2/Button/ButtonIcon.spec.tsx | 30 +
.../ui/components/v2/Button/ButtonIcon.tsx | 38 +
.../Button/__snapshots__/Button.spec.tsx.snap | 51 +
.../__snapshots__/ButtonIcon.spec.tsx.snap | 19 +
.../client/ui/components/v2/Button/index.ts | 2 +
.../ui/components/v2/CallOut/CallOut.css | 51 +
.../ui/components/v2/CallOut/CallOut.mdx | 23 +
.../ui/components/v2/CallOut/CallOut.spec.tsx | 16 +
.../ui/components/v2/CallOut/CallOut.tsx | 73 +
.../__snapshots__/CallOut.spec.tsx.snap | 11 +
.../client/ui/components/v2/CallOut/index.ts | 1 +
.../client/ui/components/v2/Card/Card.css | 18 +
.../client/ui/components/v2/Card/Card.mdx | 37 +
.../ui/components/v2/Card/Card.spec.tsx | 15 +
.../client/ui/components/v2/Card/Card.tsx | 39 +
.../ui/components/v2/Card/CloseButton.css | 8 +
.../ui/components/v2/Card/CloseButton.tsx | 41 +
.../v2/Card/__snapshots__/Card.spec.tsx.snap | 9 +
.../client/ui/components/v2/Card/index.ts | 2 +
.../ui/components/v2/CheckBox/CheckBox.css | 91 +
.../ui/components/v2/CheckBox/CheckBox.mdx | 19 +
.../components/v2/CheckBox/CheckBox.spec.tsx | 17 +
.../ui/components/v2/CheckBox/CheckBox.tsx | 90 +
.../__snapshots__/CheckBox.spec.tsx.snap | 26 +
.../client/ui/components/v2/CheckBox/index.ts | 2 +
.../v2/ClickOutside/ClickOutside.mdx | 30 +
.../v2/ClickOutside/ClickOutside.spec.tsx | 122 +
.../v2/ClickOutside/ClickOutside.tsx | 78 +
.../__snapshots__/ClickOutside.spec.tsx.snap | 3 +
.../ui/components/v2/ClickOutside/index.ts | 1 +
.../ui/components/v2/Counter/Counter.css | 56 +
.../ui/components/v2/Counter/Counter.mdx | 34 +
.../ui/components/v2/Counter/Counter.spec.tsx | 10 +
.../ui/components/v2/Counter/Counter.tsx | 65 +
.../__snapshots__/Counter.spec.tsx.snap | 24 +
.../client/ui/components/v2/Counter/index.ts | 1 +
.../client/ui/components/v2/Delay/Delay.mdx | 22 +
.../ui/components/v2/Delay/Delay.spec.tsx | 22 +
.../client/ui/components/v2/Delay/Delay.tsx | 28 +
.../Delay/__snapshots__/Delay.spec.tsx.snap | 5 +
.../client/ui/components/v2/Delay/index.ts | 1 +
.../ui/components/v2/Divider/Divider.css | 23 +
.../ui/components/v2/Divider/Divider.tsx | 23 +
.../client/ui/components/v2/Divider/index.ts | 1 +
.../ui/components/v2/Dropdown/Button.css | 55 +
.../ui/components/v2/Dropdown/Button.spec.tsx | 32 +
.../ui/components/v2/Dropdown/Button.tsx | 78 +
.../ui/components/v2/Dropdown/Divider.css | 6 +
.../components/v2/Dropdown/Divider.spec.tsx | 10 +
.../ui/components/v2/Dropdown/Divider.tsx | 17 +
.../ui/components/v2/Dropdown/Dropdown.css | 3 +
.../ui/components/v2/Dropdown/Dropdown.mdx | 58 +
.../components/v2/Dropdown/Dropdown.spec.tsx | 30 +
.../ui/components/v2/Dropdown/Dropdown.tsx | 27 +
.../__snapshots__/Button.spec.tsx.snap | 44 +
.../__snapshots__/Divider.spec.tsx.snap | 11 +
.../__snapshots__/Dropdown.spec.tsx.snap | 32 +
.../client/ui/components/v2/Dropdown/index.ts | 3 +
.../v2/DurationField/DurationField.css | 15 +
.../v2/DurationField/DurationField.spec.tsx | 71 +
.../v2/DurationField/DurationField.tsx | 176 ++
.../__snapshots__/DurationField.spec.tsx.snap | 325 +++
.../ui/components/v2/DurationField/index.ts | 1 +
.../ui/components/v2/FieldSet/FieldSet.css | 5 +
.../ui/components/v2/FieldSet/FieldSet.mdx | 10 +
.../components/v2/FieldSet/FieldSet.spec.tsx | 14 +
.../ui/components/v2/FieldSet/FieldSet.tsx | 26 +
.../__snapshots__/FieldSet.spec.tsx.snap | 9 +
.../client/ui/components/v2/FieldSet/index.ts | 1 +
.../client/ui/components/v2/Flex/Flex.css | 574 +++++
.../client/ui/components/v2/Flex/Flex.mdx | 60 +
.../ui/components/v2/Flex/Flex.spec.tsx | 68 +
.../client/ui/components/v2/Flex/Flex.tsx | 119 +
.../v2/Flex/__snapshots__/Flex.spec.tsx.snap | 51 +
.../client/ui/components/v2/Flex/index.ts | 1 +
.../ui/components/v2/FormField/FormField.css | 2 +
.../ui/components/v2/FormField/FormField.mdx | 65 +
.../v2/FormField/FormField.spec.tsx | 27 +
.../ui/components/v2/FormField/FormField.tsx | 32 +
.../__snapshots__/FormField.spec.tsx.snap | 35 +
.../ui/components/v2/FormField/index.ts | 1 +
.../FormFieldDescription.css | 7 +
.../FormFieldDescription.tsx | 17 +
.../v2/FormFieldDescription/index.ts | 1 +
.../v2/FormFieldHeader/FormFieldHeader.css | 2 +
.../v2/FormFieldHeader/FormFieldHeader.tsx | 32 +
.../ui/components/v2/FormFieldHeader/index.ts | 1 +
.../components/v2/HelperText/HelperText.css | 7 +
.../components/v2/HelperText/HelperText.tsx | 14 +
.../ui/components/v2/HelperText/index.ts | 1 +
.../v2/HorizontalGutter/HorizontalGutter.css | 85 +
.../v2/HorizontalGutter/HorizontalGutter.mdx | 36 +
.../HorizontalGutter.spec.tsx | 22 +
.../v2/HorizontalGutter/HorizontalGutter.tsx | 72 +
.../HorizontalGutter.spec.tsx.snap | 13 +
.../components/v2/HorizontalGutter/index.ts | 1 +
.../client/ui/components/v2/Icon/Icon.css | 58 +
.../client/ui/components/v2/Icon/Icon.mdx | 21 +
.../ui/components/v2/Icon/Icon.spec.tsx | 23 +
.../client/ui/components/v2/Icon/Icon.tsx | 60 +
.../v2/Icon/__snapshots__/Icon.spec.tsx.snap | 19 +
.../client/ui/components/v2/Icon/index.ts | 1 +
.../client/ui/components/v2/Label/Label.css | 9 +
.../client/ui/components/v2/Label/Label.tsx | 19 +
.../client/ui/components/v2/Label/index.ts | 1 +
.../client/ui/components/v2/Marker/Count.css | 14 +
.../ui/components/v2/Marker/Count.spec.tsx | 15 +
.../client/ui/components/v2/Marker/Count.tsx | 29 +
.../client/ui/components/v2/Marker/Marker.css | 33 +
.../client/ui/components/v2/Marker/Marker.mdx | 43 +
.../ui/components/v2/Marker/Marker.spec.tsx | 17 +
.../client/ui/components/v2/Marker/Marker.tsx | 46 +
.../Marker/__snapshots__/Count.spec.tsx.snap | 9 +
.../Marker/__snapshots__/Marker.spec.tsx.snap | 9 +
.../client/ui/components/v2/Marker/index.ts | 2 +
.../ui/components/v2/Message/Message.css | 43 +
.../ui/components/v2/Message/Message.mdx | 38 +
.../ui/components/v2/Message/Message.spec.tsx | 25 +
.../ui/components/v2/Message/Message.tsx | 59 +
.../ui/components/v2/Message/MessageIcon.css | 8 +
.../ui/components/v2/Message/MessageIcon.tsx | 37 +
.../__snapshots__/Message.spec.tsx.snap | 23 +
.../client/ui/components/v2/Message/index.ts | 2 +
.../client/ui/components/v2/Modal/Modal.css | 32 +
.../client/ui/components/v2/Modal/Modal.mdx | 66 +
.../ui/components/v2/Modal/Modal.mdx.css | 3 +
.../ui/components/v2/Modal/Modal.spec.tsx | 90 +
.../client/ui/components/v2/Modal/Modal.tsx | 132 ++
.../Modal/__snapshots__/Modal.spec.tsx.snap | 46 +
.../client/ui/components/v2/Modal/index.ts | 1 +
.../ui/components/v2/NoScroll/NoScroll.css | 3 +
.../ui/components/v2/NoScroll/NoScroll.mdx | 35 +
.../components/v2/NoScroll/NoScroll.spec.tsx | 52 +
.../ui/components/v2/NoScroll/NoScroll.tsx | 41 +
.../client/ui/components/v2/NoScroll/index.ts | 1 +
.../v2/PasswordField/PasswordField.css | 69 +
.../v2/PasswordField/PasswordField.mdx | 25 +
.../v2/PasswordField/PasswordField.spec.tsx | 18 +
.../v2/PasswordField/PasswordField.tsx | 162 ++
.../__snapshots__/PasswordField.spec.tsx.snap | 73 +
.../ui/components/v2/PasswordField/index.ts | 2 +
.../client/ui/components/v2/Popover/Arrow.css | 142 ++
.../client/ui/components/v2/Popover/Arrow.tsx | 26 +
.../ui/components/v2/Popover/Popover.css | 30 +
.../ui/components/v2/Popover/Popover.mdx | 88 +
.../ui/components/v2/Popover/Popover.tsx | 202 ++
.../client/ui/components/v2/Popover/index.ts | 1 +
.../components/v2/RadioButton/RadioButton.css | 80 +
.../components/v2/RadioButton/RadioButton.mdx | 20 +
.../v2/RadioButton/RadioButton.spec.tsx | 18 +
.../components/v2/RadioButton/RadioButton.tsx | 89 +
.../__snapshots__/RadioButton.spec.tsx.snap | 23 +
.../ui/components/v2/RadioButton/index.ts | 2 +
.../v2/RelativeTime/RelativeTime.css | 2 +
.../v2/RelativeTime/RelativeTime.mdx | 17 +
.../v2/RelativeTime/RelativeTime.spec.tsx | 42 +
.../v2/RelativeTime/RelativeTime.tsx | 43 +
.../__snapshots__/RelativeTime.spec.tsx.snap | 31 +
.../ui/components/v2/RelativeTime/index.ts | 1 +
.../v2/SelectField/OptGroup.spec.tsx | 14 +
.../ui/components/v2/SelectField/OptGroup.tsx | 12 +
.../components/v2/SelectField/Option.spec.tsx | 16 +
.../ui/components/v2/SelectField/Option.tsx | 14 +
.../components/v2/SelectField/SelectField.css | 63 +
.../components/v2/SelectField/SelectField.mdx | 52 +
.../v2/SelectField/SelectField.spec.tsx | 21 +
.../components/v2/SelectField/SelectField.tsx | 86 +
.../__snapshots__/OptGroup.spec.tsx.snap | 9 +
.../__snapshots__/Option.spec.tsx.snap | 11 +
.../__snapshots__/SelectField.spec.tsx.snap | 30 +
.../ui/components/v2/SelectField/index.ts | 3 +
.../ui/components/v2/Spinner/Spinner.css | 63 +
.../ui/components/v2/Spinner/Spinner.mdx | 15 +
.../ui/components/v2/Spinner/Spinner.spec.tsx | 9 +
.../ui/components/v2/Spinner/Spinner.tsx | 68 +
.../__snapshots__/Spinner.spec.tsx.snap | 21 +
.../client/ui/components/v2/Spinner/index.ts | 1 +
.../ui/components/v2/SubBar/Navigation.css | 20 +
.../components/v2/SubBar/Navigation.spec.tsx | 15 +
.../ui/components/v2/SubBar/Navigation.tsx | 24 +
.../components/v2/SubBar/NavigationItem.css | 36 +
.../v2/SubBar/NavigationItem.spec.tsx | 20 +
.../components/v2/SubBar/NavigationItem.tsx | 41 +
.../client/ui/components/v2/SubBar/SubBar.css | 22 +
.../client/ui/components/v2/SubBar/SubBar.mdx | 40 +
.../ui/components/v2/SubBar/SubBar.spec.tsx | 18 +
.../client/ui/components/v2/SubBar/SubBar.tsx | 44 +
.../__snapshots__/Navigation.spec.tsx.snap | 14 +
.../NavigationItem.spec.tsx.snap | 19 +
.../SubBar/__snapshots__/SubBar.spec.tsx.snap | 19 +
.../client/ui/components/v2/SubBar/index.ts | 3 +
.../client/ui/components/v2/Table/Table.css | 8 +
.../client/ui/components/v2/Table/Table.mdx | 36 +
.../ui/components/v2/Table/Table.spec.tsx | 32 +
.../client/ui/components/v2/Table/Table.tsx | 36 +
.../ui/components/v2/Table/TableBody.css | 2 +
.../ui/components/v2/Table/TableBody.tsx | 31 +
.../ui/components/v2/Table/TableCell.css | 32 +
.../ui/components/v2/Table/TableCell.tsx | 45 +
.../ui/components/v2/Table/TableHead.css | 4 +
.../ui/components/v2/Table/TableHead.tsx | 35 +
.../ui/components/v2/Table/TableRow.css | 11 +
.../ui/components/v2/Table/TableRow.tsx | 36 +
.../Table/__snapshots__/Table.spec.tsx.snap | 51 +
.../client/ui/components/v2/Table/index.ts | 5 +
src/core/client/ui/components/v2/Tabs/Tab.css | 72 +
.../client/ui/components/v2/Tabs/Tab.spec.tsx | 9 +
src/core/client/ui/components/v2/Tabs/Tab.tsx | 80 +
.../client/ui/components/v2/Tabs/TabBar.css | 17 +
.../ui/components/v2/Tabs/TabBar.spec.tsx | 34 +
.../client/ui/components/v2/Tabs/TabBar.tsx | 83 +
.../ui/components/v2/Tabs/TabContent.spec.tsx | 31 +
.../ui/components/v2/Tabs/TabContent.tsx | 33 +
.../ui/components/v2/Tabs/TabPane.spec.tsx | 9 +
.../client/ui/components/v2/Tabs/TabPane.tsx | 30 +
.../v2/Tabs/__snapshots__/Tab.spec.tsx.snap | 24 +
.../Tabs/__snapshots__/TabBar.spec.tsx.snap | 72 +
.../__snapshots__/TabContent.spec.tsx.snap | 12 +
.../Tabs/__snapshots__/TabPane.spec.tsx.snap | 11 +
.../client/ui/components/v2/Tabs/index.ts | 4 +
.../client/ui/components/v2/Tabs/tabs.mdx | 63 +
src/core/client/ui/components/v2/Tag/Tag.css | 64 +
src/core/client/ui/components/v2/Tag/Tag.mdx | 35 +
.../client/ui/components/v2/Tag/Tag.spec.tsx | 15 +
src/core/client/ui/components/v2/Tag/Tag.tsx | 45 +
.../v2/Tag/__snapshots__/Tag.spec.tsx.snap | 9 +
src/core/client/ui/components/v2/Tag/index.ts | 1 +
.../ui/components/v2/TextField/TextField.css | 97 +
.../ui/components/v2/TextField/TextField.mdx | 43 +
.../v2/TextField/TextField.spec.tsx | 16 +
.../ui/components/v2/TextField/TextField.tsx | 119 +
.../__snapshots__/TextField.spec.tsx.snap | 19 +
.../ui/components/v2/TextField/index.ts | 2 +
.../TextFieldAdornment/TextFieldAdornment.css | 7 +
.../TextFieldAdornment/TextFieldAdornment.tsx | 17 +
.../components/v2/TextFieldAdornment/index.ts | 1 +
.../ui/components/v2/TextLink/TextLink.css | 10 +
.../ui/components/v2/TextLink/TextLink.mdx | 19 +
.../components/v2/TextLink/TextLink.spec.tsx | 14 +
.../ui/components/v2/TextLink/TextLink.tsx | 38 +
.../__snapshots__/TextLink.spec.tsx.snap | 10 +
.../client/ui/components/v2/TextLink/index.ts | 1 +
.../ui/components/v2/Textarea/Textarea.css | 28 +
.../ui/components/v2/Textarea/Textarea.tsx | 31 +
.../client/ui/components/v2/Textarea/index.ts | 1 +
.../ui/components/v2/Timestamp/Timestamp.css | 11 +
.../v2/Timestamp/Timestamp.spec.tsx | 15 +
.../ui/components/v2/Timestamp/Timestamp.tsx | 42 +
.../__snapshots__/Timestamp.spec.tsx.snap | 13 +
.../ui/components/v2/Timestamp/index.ts | 1 +
.../ui/components/v2/Tooltip/Tooltip.css | 29 +
.../ui/components/v2/Tooltip/Tooltip.tsx | 53 +
.../components/v2/Tooltip/TooltipButton.css | 7 +
.../components/v2/Tooltip/TooltipButton.tsx | 39 +
.../client/ui/components/v2/Tooltip/index.ts | 2 +
.../ui/components/v2/TrapFocus/TrapFocus.mdx | 27 +
.../v2/TrapFocus/TrapFocus.spec.tsx | 94 +
.../ui/components/v2/TrapFocus/TrapFocus.tsx | 59 +
.../__snapshots__/TrapFocus.spec.tsx.snap | 23 +
.../ui/components/v2/TrapFocus/index.ts | 1 +
.../ui/components/v2/UIContext/UIContext.ts | 21 +
.../ui/components/v2/UIContext/index.ts | 1 +
.../ValidationMessage/ValidationMessage.mdx | 20 +
.../ValidationMessage.spec.tsx | 15 +
.../ValidationMessage/ValidationMessage.tsx | 41 +
.../ValidationMessage.spec.tsx.snap | 15 +
.../components/v2/ValidationMessage/index.ts | 1 +
src/core/client/ui/components/v2/index.ts | 65 +
src/core/client/ui/shared/typography.css | 62 +
src/core/client/ui/theme/mixins.css | 10 +
src/core/client/ui/theme/variables.css.ts | 13 +-
src/core/client/ui/theme/variables2.ts | 320 +++
src/locales/en-US/admin.ftl | 7 +-
src/locales/pt-BR/admin.ftl | 2 +-
625 files changed, 20631 insertions(+), 7766 deletions(-)
create mode 100644 src/core/client/admin/App/DecisionHistory/Username.css
create mode 100644 src/core/client/admin/App/DecisionHistory/Username.tsx
create mode 100644 src/core/client/admin/components/UserStatus/ChangeStatusModal.css
create mode 100644 src/core/client/admin/components/UserStatus/ChangeStatusModal.tsx
create mode 100644 src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.css
create mode 100644 src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.tsx
create mode 100644 src/core/client/admin/components/UserStatus/ModalHeaderUsername.css
create mode 100644 src/core/client/admin/components/UserStatus/ModalHeaderUsername.tsx
create mode 100644 src/core/client/admin/components/UserStatus/SuspendForm.css
create mode 100644 src/core/client/admin/components/UserStatus/UserStatus.css
create mode 100644 src/core/client/admin/routes/Community/InviteUsers/InviteUsers.css
create mode 100644 src/core/client/admin/routes/Community/InviteUsers/InviteUsersForm.css
create mode 100644 src/core/client/admin/routes/Community/InviteUsers/RoleField.css
create mode 100644 src/core/client/admin/routes/Configure/Fields/LocaleField.tsx
create mode 100644 src/core/client/admin/routes/Configure/HelperText.css
create mode 100644 src/core/client/admin/routes/Configure/HelperText.tsx
create mode 100644 src/core/client/admin/routes/Configure/TextFieldWithValidation.css
create mode 100644 src/core/client/admin/routes/Configure/TextFieldWithValidation.tsx
delete mode 100644 src/core/client/admin/routes/Configure/sections/Auth/ConfigDescription.tsx
create mode 100644 src/core/client/admin/routes/Moderate/ModerateSearchBar/variables.css
create mode 100644 src/core/client/admin/routes/NotFound.css
create mode 100644 src/core/client/admin/ui/components/index.ts
create mode 100644 src/core/client/ui/components/v2/AppBar/AppBar.css
create mode 100644 src/core/client/ui/components/v2/AppBar/AppBar.mdx
create mode 100644 src/core/client/ui/components/v2/AppBar/AppBar.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/AppBar.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Begin.css
create mode 100644 src/core/client/ui/components/v2/AppBar/Begin.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Begin.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Divider.css
create mode 100644 src/core/client/ui/components/v2/AppBar/Divider.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Divider.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/End.css
create mode 100644 src/core/client/ui/components/v2/AppBar/End.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/End.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Navigation.css
create mode 100644 src/core/client/ui/components/v2/AppBar/Navigation.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/Navigation.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/NavigationItem.css
create mode 100644 src/core/client/ui/components/v2/AppBar/NavigationItem.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/NavigationItem.tsx
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/AppBar.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/Begin.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/Divider.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/End.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/Navigation.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/__snapshots__/NavigationItem.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AppBar/index.ts
create mode 100644 src/core/client/ui/components/v2/AriaInfo/AriaInfo.css
create mode 100644 src/core/client/ui/components/v2/AriaInfo/AriaInfo.mdx
create mode 100644 src/core/client/ui/components/v2/AriaInfo/AriaInfo.spec.tsx
create mode 100644 src/core/client/ui/components/v2/AriaInfo/AriaInfo.tsx
create mode 100644 src/core/client/ui/components/v2/AriaInfo/__snapshots__/AriaInfo.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/AriaInfo/index.ts
create mode 100644 src/core/client/ui/components/v2/Backdrop/Backdrop.css
create mode 100644 src/core/client/ui/components/v2/Backdrop/Backdrop.mdx
create mode 100644 src/core/client/ui/components/v2/Backdrop/Backdrop.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Backdrop/Backdrop.tsx
create mode 100644 src/core/client/ui/components/v2/Backdrop/__snapshots__/Backdrop.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Backdrop/index.ts
create mode 100644 src/core/client/ui/components/v2/BaseButton/BaseButton.css
create mode 100644 src/core/client/ui/components/v2/BaseButton/BaseButton.mdx
create mode 100644 src/core/client/ui/components/v2/BaseButton/BaseButton.spec.tsx
create mode 100644 src/core/client/ui/components/v2/BaseButton/BaseButton.tsx
create mode 100644 src/core/client/ui/components/v2/BaseButton/__snapshots__/BaseButton.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/BaseButton/index.ts
create mode 100644 src/core/client/ui/components/v2/Box/Box.css
create mode 100644 src/core/client/ui/components/v2/Box/Box.mdx
create mode 100644 src/core/client/ui/components/v2/Box/Box.tsx
create mode 100644 src/core/client/ui/components/v2/Box/index.ts
create mode 100644 src/core/client/ui/components/v2/Button/Button.css
create mode 100644 src/core/client/ui/components/v2/Button/Button.mdx
create mode 100644 src/core/client/ui/components/v2/Button/Button.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Button/Button.tsx
create mode 100644 src/core/client/ui/components/v2/Button/ButtonIcon.css
create mode 100644 src/core/client/ui/components/v2/Button/ButtonIcon.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Button/ButtonIcon.tsx
create mode 100644 src/core/client/ui/components/v2/Button/__snapshots__/Button.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Button/__snapshots__/ButtonIcon.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Button/index.ts
create mode 100644 src/core/client/ui/components/v2/CallOut/CallOut.css
create mode 100644 src/core/client/ui/components/v2/CallOut/CallOut.mdx
create mode 100644 src/core/client/ui/components/v2/CallOut/CallOut.spec.tsx
create mode 100644 src/core/client/ui/components/v2/CallOut/CallOut.tsx
create mode 100644 src/core/client/ui/components/v2/CallOut/__snapshots__/CallOut.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/CallOut/index.ts
create mode 100644 src/core/client/ui/components/v2/Card/Card.css
create mode 100644 src/core/client/ui/components/v2/Card/Card.mdx
create mode 100644 src/core/client/ui/components/v2/Card/Card.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Card/Card.tsx
create mode 100644 src/core/client/ui/components/v2/Card/CloseButton.css
create mode 100644 src/core/client/ui/components/v2/Card/CloseButton.tsx
create mode 100644 src/core/client/ui/components/v2/Card/__snapshots__/Card.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Card/index.ts
create mode 100644 src/core/client/ui/components/v2/CheckBox/CheckBox.css
create mode 100644 src/core/client/ui/components/v2/CheckBox/CheckBox.mdx
create mode 100644 src/core/client/ui/components/v2/CheckBox/CheckBox.spec.tsx
create mode 100644 src/core/client/ui/components/v2/CheckBox/CheckBox.tsx
create mode 100644 src/core/client/ui/components/v2/CheckBox/__snapshots__/CheckBox.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/CheckBox/index.ts
create mode 100644 src/core/client/ui/components/v2/ClickOutside/ClickOutside.mdx
create mode 100644 src/core/client/ui/components/v2/ClickOutside/ClickOutside.spec.tsx
create mode 100644 src/core/client/ui/components/v2/ClickOutside/ClickOutside.tsx
create mode 100644 src/core/client/ui/components/v2/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/ClickOutside/index.ts
create mode 100644 src/core/client/ui/components/v2/Counter/Counter.css
create mode 100644 src/core/client/ui/components/v2/Counter/Counter.mdx
create mode 100644 src/core/client/ui/components/v2/Counter/Counter.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Counter/Counter.tsx
create mode 100644 src/core/client/ui/components/v2/Counter/__snapshots__/Counter.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Counter/index.ts
create mode 100644 src/core/client/ui/components/v2/Delay/Delay.mdx
create mode 100644 src/core/client/ui/components/v2/Delay/Delay.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Delay/Delay.tsx
create mode 100644 src/core/client/ui/components/v2/Delay/__snapshots__/Delay.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Delay/index.ts
create mode 100644 src/core/client/ui/components/v2/Divider/Divider.css
create mode 100644 src/core/client/ui/components/v2/Divider/Divider.tsx
create mode 100644 src/core/client/ui/components/v2/Divider/index.ts
create mode 100644 src/core/client/ui/components/v2/Dropdown/Button.css
create mode 100644 src/core/client/ui/components/v2/Dropdown/Button.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Button.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Divider.css
create mode 100644 src/core/client/ui/components/v2/Dropdown/Divider.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Divider.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Dropdown.css
create mode 100644 src/core/client/ui/components/v2/Dropdown/Dropdown.mdx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Dropdown.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/Dropdown.tsx
create mode 100644 src/core/client/ui/components/v2/Dropdown/__snapshots__/Button.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Dropdown/__snapshots__/Divider.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Dropdown/__snapshots__/Dropdown.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Dropdown/index.ts
create mode 100644 src/core/client/ui/components/v2/DurationField/DurationField.css
create mode 100644 src/core/client/ui/components/v2/DurationField/DurationField.spec.tsx
create mode 100644 src/core/client/ui/components/v2/DurationField/DurationField.tsx
create mode 100644 src/core/client/ui/components/v2/DurationField/__snapshots__/DurationField.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/DurationField/index.ts
create mode 100644 src/core/client/ui/components/v2/FieldSet/FieldSet.css
create mode 100644 src/core/client/ui/components/v2/FieldSet/FieldSet.mdx
create mode 100644 src/core/client/ui/components/v2/FieldSet/FieldSet.spec.tsx
create mode 100644 src/core/client/ui/components/v2/FieldSet/FieldSet.tsx
create mode 100644 src/core/client/ui/components/v2/FieldSet/__snapshots__/FieldSet.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/FieldSet/index.ts
create mode 100644 src/core/client/ui/components/v2/Flex/Flex.css
create mode 100644 src/core/client/ui/components/v2/Flex/Flex.mdx
create mode 100644 src/core/client/ui/components/v2/Flex/Flex.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Flex/Flex.tsx
create mode 100644 src/core/client/ui/components/v2/Flex/__snapshots__/Flex.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Flex/index.ts
create mode 100644 src/core/client/ui/components/v2/FormField/FormField.css
create mode 100644 src/core/client/ui/components/v2/FormField/FormField.mdx
create mode 100644 src/core/client/ui/components/v2/FormField/FormField.spec.tsx
create mode 100644 src/core/client/ui/components/v2/FormField/FormField.tsx
create mode 100644 src/core/client/ui/components/v2/FormField/__snapshots__/FormField.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/FormField/index.ts
create mode 100644 src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.css
create mode 100644 src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.tsx
create mode 100644 src/core/client/ui/components/v2/FormFieldDescription/index.ts
create mode 100644 src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.css
create mode 100644 src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.tsx
create mode 100644 src/core/client/ui/components/v2/FormFieldHeader/index.ts
create mode 100644 src/core/client/ui/components/v2/HelperText/HelperText.css
create mode 100644 src/core/client/ui/components/v2/HelperText/HelperText.tsx
create mode 100644 src/core/client/ui/components/v2/HelperText/index.ts
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.css
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.mdx
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.spec.tsx
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.tsx
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/__snapshots__/HorizontalGutter.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/HorizontalGutter/index.ts
create mode 100644 src/core/client/ui/components/v2/Icon/Icon.css
create mode 100644 src/core/client/ui/components/v2/Icon/Icon.mdx
create mode 100644 src/core/client/ui/components/v2/Icon/Icon.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Icon/Icon.tsx
create mode 100644 src/core/client/ui/components/v2/Icon/__snapshots__/Icon.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Icon/index.ts
create mode 100644 src/core/client/ui/components/v2/Label/Label.css
create mode 100644 src/core/client/ui/components/v2/Label/Label.tsx
create mode 100644 src/core/client/ui/components/v2/Label/index.ts
create mode 100644 src/core/client/ui/components/v2/Marker/Count.css
create mode 100644 src/core/client/ui/components/v2/Marker/Count.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Marker/Count.tsx
create mode 100644 src/core/client/ui/components/v2/Marker/Marker.css
create mode 100644 src/core/client/ui/components/v2/Marker/Marker.mdx
create mode 100644 src/core/client/ui/components/v2/Marker/Marker.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Marker/Marker.tsx
create mode 100644 src/core/client/ui/components/v2/Marker/__snapshots__/Count.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Marker/__snapshots__/Marker.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Marker/index.ts
create mode 100644 src/core/client/ui/components/v2/Message/Message.css
create mode 100644 src/core/client/ui/components/v2/Message/Message.mdx
create mode 100644 src/core/client/ui/components/v2/Message/Message.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Message/Message.tsx
create mode 100644 src/core/client/ui/components/v2/Message/MessageIcon.css
create mode 100644 src/core/client/ui/components/v2/Message/MessageIcon.tsx
create mode 100644 src/core/client/ui/components/v2/Message/__snapshots__/Message.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Message/index.ts
create mode 100644 src/core/client/ui/components/v2/Modal/Modal.css
create mode 100644 src/core/client/ui/components/v2/Modal/Modal.mdx
create mode 100644 src/core/client/ui/components/v2/Modal/Modal.mdx.css
create mode 100644 src/core/client/ui/components/v2/Modal/Modal.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Modal/Modal.tsx
create mode 100644 src/core/client/ui/components/v2/Modal/__snapshots__/Modal.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Modal/index.ts
create mode 100644 src/core/client/ui/components/v2/NoScroll/NoScroll.css
create mode 100644 src/core/client/ui/components/v2/NoScroll/NoScroll.mdx
create mode 100644 src/core/client/ui/components/v2/NoScroll/NoScroll.spec.tsx
create mode 100644 src/core/client/ui/components/v2/NoScroll/NoScroll.tsx
create mode 100644 src/core/client/ui/components/v2/NoScroll/index.ts
create mode 100644 src/core/client/ui/components/v2/PasswordField/PasswordField.css
create mode 100644 src/core/client/ui/components/v2/PasswordField/PasswordField.mdx
create mode 100644 src/core/client/ui/components/v2/PasswordField/PasswordField.spec.tsx
create mode 100644 src/core/client/ui/components/v2/PasswordField/PasswordField.tsx
create mode 100644 src/core/client/ui/components/v2/PasswordField/__snapshots__/PasswordField.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/PasswordField/index.ts
create mode 100644 src/core/client/ui/components/v2/Popover/Arrow.css
create mode 100644 src/core/client/ui/components/v2/Popover/Arrow.tsx
create mode 100644 src/core/client/ui/components/v2/Popover/Popover.css
create mode 100644 src/core/client/ui/components/v2/Popover/Popover.mdx
create mode 100644 src/core/client/ui/components/v2/Popover/Popover.tsx
create mode 100644 src/core/client/ui/components/v2/Popover/index.ts
create mode 100644 src/core/client/ui/components/v2/RadioButton/RadioButton.css
create mode 100644 src/core/client/ui/components/v2/RadioButton/RadioButton.mdx
create mode 100644 src/core/client/ui/components/v2/RadioButton/RadioButton.spec.tsx
create mode 100644 src/core/client/ui/components/v2/RadioButton/RadioButton.tsx
create mode 100644 src/core/client/ui/components/v2/RadioButton/__snapshots__/RadioButton.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/RadioButton/index.ts
create mode 100644 src/core/client/ui/components/v2/RelativeTime/RelativeTime.css
create mode 100644 src/core/client/ui/components/v2/RelativeTime/RelativeTime.mdx
create mode 100644 src/core/client/ui/components/v2/RelativeTime/RelativeTime.spec.tsx
create mode 100644 src/core/client/ui/components/v2/RelativeTime/RelativeTime.tsx
create mode 100644 src/core/client/ui/components/v2/RelativeTime/__snapshots__/RelativeTime.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/RelativeTime/index.ts
create mode 100644 src/core/client/ui/components/v2/SelectField/OptGroup.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/OptGroup.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/Option.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/Option.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/SelectField.css
create mode 100644 src/core/client/ui/components/v2/SelectField/SelectField.mdx
create mode 100644 src/core/client/ui/components/v2/SelectField/SelectField.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/SelectField.tsx
create mode 100644 src/core/client/ui/components/v2/SelectField/__snapshots__/OptGroup.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SelectField/__snapshots__/Option.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SelectField/__snapshots__/SelectField.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SelectField/index.ts
create mode 100644 src/core/client/ui/components/v2/Spinner/Spinner.css
create mode 100644 src/core/client/ui/components/v2/Spinner/Spinner.mdx
create mode 100644 src/core/client/ui/components/v2/Spinner/Spinner.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Spinner/Spinner.tsx
create mode 100644 src/core/client/ui/components/v2/Spinner/__snapshots__/Spinner.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Spinner/index.ts
create mode 100644 src/core/client/ui/components/v2/SubBar/Navigation.css
create mode 100644 src/core/client/ui/components/v2/SubBar/Navigation.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/Navigation.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/NavigationItem.css
create mode 100644 src/core/client/ui/components/v2/SubBar/NavigationItem.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/NavigationItem.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/SubBar.css
create mode 100644 src/core/client/ui/components/v2/SubBar/SubBar.mdx
create mode 100644 src/core/client/ui/components/v2/SubBar/SubBar.spec.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/SubBar.tsx
create mode 100644 src/core/client/ui/components/v2/SubBar/__snapshots__/Navigation.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SubBar/__snapshots__/NavigationItem.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SubBar/__snapshots__/SubBar.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/SubBar/index.ts
create mode 100644 src/core/client/ui/components/v2/Table/Table.css
create mode 100644 src/core/client/ui/components/v2/Table/Table.mdx
create mode 100644 src/core/client/ui/components/v2/Table/Table.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Table/Table.tsx
create mode 100644 src/core/client/ui/components/v2/Table/TableBody.css
create mode 100644 src/core/client/ui/components/v2/Table/TableBody.tsx
create mode 100644 src/core/client/ui/components/v2/Table/TableCell.css
create mode 100644 src/core/client/ui/components/v2/Table/TableCell.tsx
create mode 100644 src/core/client/ui/components/v2/Table/TableHead.css
create mode 100644 src/core/client/ui/components/v2/Table/TableHead.tsx
create mode 100644 src/core/client/ui/components/v2/Table/TableRow.css
create mode 100644 src/core/client/ui/components/v2/Table/TableRow.tsx
create mode 100644 src/core/client/ui/components/v2/Table/__snapshots__/Table.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Table/index.ts
create mode 100644 src/core/client/ui/components/v2/Tabs/Tab.css
create mode 100644 src/core/client/ui/components/v2/Tabs/Tab.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/Tab.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabBar.css
create mode 100644 src/core/client/ui/components/v2/Tabs/TabBar.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabBar.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabContent.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabContent.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabPane.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/TabPane.tsx
create mode 100644 src/core/client/ui/components/v2/Tabs/__snapshots__/Tab.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Tabs/__snapshots__/TabBar.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Tabs/__snapshots__/TabContent.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Tabs/__snapshots__/TabPane.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Tabs/index.ts
create mode 100644 src/core/client/ui/components/v2/Tabs/tabs.mdx
create mode 100644 src/core/client/ui/components/v2/Tag/Tag.css
create mode 100644 src/core/client/ui/components/v2/Tag/Tag.mdx
create mode 100644 src/core/client/ui/components/v2/Tag/Tag.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Tag/Tag.tsx
create mode 100644 src/core/client/ui/components/v2/Tag/__snapshots__/Tag.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Tag/index.ts
create mode 100644 src/core/client/ui/components/v2/TextField/TextField.css
create mode 100644 src/core/client/ui/components/v2/TextField/TextField.mdx
create mode 100644 src/core/client/ui/components/v2/TextField/TextField.spec.tsx
create mode 100644 src/core/client/ui/components/v2/TextField/TextField.tsx
create mode 100644 src/core/client/ui/components/v2/TextField/__snapshots__/TextField.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/TextField/index.ts
create mode 100644 src/core/client/ui/components/v2/TextFieldAdornment/TextFieldAdornment.css
create mode 100644 src/core/client/ui/components/v2/TextFieldAdornment/TextFieldAdornment.tsx
create mode 100644 src/core/client/ui/components/v2/TextFieldAdornment/index.ts
create mode 100644 src/core/client/ui/components/v2/TextLink/TextLink.css
create mode 100644 src/core/client/ui/components/v2/TextLink/TextLink.mdx
create mode 100644 src/core/client/ui/components/v2/TextLink/TextLink.spec.tsx
create mode 100644 src/core/client/ui/components/v2/TextLink/TextLink.tsx
create mode 100644 src/core/client/ui/components/v2/TextLink/__snapshots__/TextLink.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/TextLink/index.ts
create mode 100644 src/core/client/ui/components/v2/Textarea/Textarea.css
create mode 100644 src/core/client/ui/components/v2/Textarea/Textarea.tsx
create mode 100644 src/core/client/ui/components/v2/Textarea/index.ts
create mode 100644 src/core/client/ui/components/v2/Timestamp/Timestamp.css
create mode 100644 src/core/client/ui/components/v2/Timestamp/Timestamp.spec.tsx
create mode 100644 src/core/client/ui/components/v2/Timestamp/Timestamp.tsx
create mode 100644 src/core/client/ui/components/v2/Timestamp/__snapshots__/Timestamp.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/Timestamp/index.ts
create mode 100644 src/core/client/ui/components/v2/Tooltip/Tooltip.css
create mode 100644 src/core/client/ui/components/v2/Tooltip/Tooltip.tsx
create mode 100644 src/core/client/ui/components/v2/Tooltip/TooltipButton.css
create mode 100644 src/core/client/ui/components/v2/Tooltip/TooltipButton.tsx
create mode 100644 src/core/client/ui/components/v2/Tooltip/index.ts
create mode 100644 src/core/client/ui/components/v2/TrapFocus/TrapFocus.mdx
create mode 100644 src/core/client/ui/components/v2/TrapFocus/TrapFocus.spec.tsx
create mode 100644 src/core/client/ui/components/v2/TrapFocus/TrapFocus.tsx
create mode 100644 src/core/client/ui/components/v2/TrapFocus/__snapshots__/TrapFocus.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/TrapFocus/index.ts
create mode 100644 src/core/client/ui/components/v2/UIContext/UIContext.ts
create mode 100644 src/core/client/ui/components/v2/UIContext/index.ts
create mode 100644 src/core/client/ui/components/v2/ValidationMessage/ValidationMessage.mdx
create mode 100644 src/core/client/ui/components/v2/ValidationMessage/ValidationMessage.spec.tsx
create mode 100644 src/core/client/ui/components/v2/ValidationMessage/ValidationMessage.tsx
create mode 100644 src/core/client/ui/components/v2/ValidationMessage/__snapshots__/ValidationMessage.spec.tsx.snap
create mode 100644 src/core/client/ui/components/v2/ValidationMessage/index.ts
create mode 100644 src/core/client/ui/components/v2/index.ts
create mode 100644 src/core/client/ui/theme/variables2.ts
diff --git a/package-lock.json b/package-lock.json
index 6d1a9a28c..c9823ebb0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -34509,6 +34509,18 @@
"integrity": "sha512-oaqDlrGz0dhBvNlt6iEtWWs6zFSodhxPlYzK3gDoEBTAQvImWipOqeb4u2XI77sY+UZkS1wu6kAxJYUMySJ+iQ==",
"dev": true
},
+ "typeface-nunito": {
+ "version": "0.0.72",
+ "resolved": "https://registry.npmjs.org/typeface-nunito/-/typeface-nunito-0.0.72.tgz",
+ "integrity": "sha512-id43vYQiM9emQ6sbysLDRp8fb39Dk5yW/q6uSPHJnE1XVDSfrxYWFg/YiSoiaK+kO7wbuWb2HSjCAfH96Mabvg==",
+ "dev": true
+ },
+ "typeface-open-sans": {
+ "version": "0.0.75",
+ "resolved": "https://registry.npmjs.org/typeface-open-sans/-/typeface-open-sans-0.0.75.tgz",
+ "integrity": "sha512-0lLmB7pfj113OP4T78SbpSmC4OCdFQ0vUxdSXQccsSb6qF76F92iEuC/DghFgmPswTyidk8+Hwf+PS/htiJoRQ==",
+ "dev": true
+ },
"typeface-source-sans-pro": {
"version": "0.0.54",
"resolved": "https://registry.npmjs.org/typeface-source-sans-pro/-/typeface-source-sans-pro-0.0.54.tgz",
diff --git a/package.json b/package.json
index 415595e35..776c8bb13 100644
--- a/package.json
+++ b/package.json
@@ -365,6 +365,8 @@
"typeface-source-sans-pro": "^0.0.54",
"typescript": "3.3.4000",
"typescript-snapshots-plugin": "^1.6.0",
+ "typeface-nunito": "0.0.72",
+ "typeface-open-sans": "0.0.75",
"wait-for-expect": "^1.1.1",
"webpack": "^4.30.0",
"webpack-assets-manifest": "^3.1.1",
diff --git a/src/core/client/admin/App/DecisionHistory/ApprovedComment.tsx b/src/core/client/admin/App/DecisionHistory/ApprovedComment.tsx
index a8f3cf3f8..a23651f5d 100644
--- a/src/core/client/admin/App/DecisionHistory/ApprovedComment.tsx
+++ b/src/core/client/admin/App/DecisionHistory/ApprovedComment.tsx
@@ -1,8 +1,6 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import ApprovedIcon from "./ApprovedIcon";
import DecisionItem from "./DecisionItem";
import DotDivider from "./DotDivider";
@@ -10,6 +8,7 @@ import Footer from "./Footer";
import GoToCommentLink from "./GoToCommentLink";
import Info from "./Info";
import Timestamp from "./Timestamp";
+import Username from "./Username";
interface Props {
href: string;
@@ -18,10 +17,6 @@ interface Props {
onGotoComment?: React.EventHandler;
}
-const Username: FunctionComponent<{ username: string }> = ({ username }) => (
- {username}
-);
-
const ApprovedComment: FunctionComponent = props => (
}>
= props => (
{"Approved comment by "}
-
- {props.date}
-
+ {props.date}
diff --git a/src/core/client/admin/App/DecisionHistory/ApprovedIcon.css b/src/core/client/admin/App/DecisionHistory/ApprovedIcon.css
index 50efdc1dc..f9cae42f2 100644
--- a/src/core/client/admin/App/DecisionHistory/ApprovedIcon.css
+++ b/src/core/client/admin/App/DecisionHistory/ApprovedIcon.css
@@ -1,3 +1,3 @@
.root {
- color: var(--palette-success-main);
+ color: var(--v2-palette-success-main);
}
diff --git a/src/core/client/admin/App/DecisionHistory/ApprovedIcon.tsx b/src/core/client/admin/App/DecisionHistory/ApprovedIcon.tsx
index 03f80790b..3c6b1b255 100644
--- a/src/core/client/admin/App/DecisionHistory/ApprovedIcon.tsx
+++ b/src/core/client/admin/App/DecisionHistory/ApprovedIcon.tsx
@@ -1,11 +1,13 @@
import React, { FunctionComponent } from "react";
-import { Icon } from "coral-ui/components";
+import { Icon } from "coral-ui/components/v2";
import styles from "./ApprovedIcon.css";
const ApprovedIcon: FunctionComponent = () => (
- check
+
+ check_circled
+
);
export default ApprovedIcon;
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.css b/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.css
index 84f602e5d..91a29eff9 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.css
+++ b/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.css
@@ -3,6 +3,6 @@
}
.historyIcon {
- color: var(--palette-text-secondary);
- margin-right: calc(1.5 * var(--mini-unit));
+ color: var(--v2-palette-text-secondary);
+ margin-right: 10px;
}
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.tsx b/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.tsx
index e712722c9..15dfc595c 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.tsx
+++ b/src/core/client/admin/App/DecisionHistory/DecisionHistoryButton.tsx
@@ -1,7 +1,12 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { BaseButton, ClickOutside, Icon, Popover } from "coral-ui/components";
+import {
+ BaseButton,
+ ClickOutside,
+ Icon,
+ Popover,
+} from "coral-ui/components/v2";
import DecisionHistoryQuery from "./DecisionHistoryQuery";
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionHistoryLoading.tsx b/src/core/client/admin/App/DecisionHistory/DecisionHistoryLoading.tsx
index 61f3dacf7..939bf45db 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionHistoryLoading.tsx
+++ b/src/core/client/admin/App/DecisionHistory/DecisionHistoryLoading.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { Delay, Flex, Spinner } from "coral-ui/components";
+import { Delay, Flex, Spinner } from "coral-ui/components/v2";
import Main from "./Main";
import Title from "./Title";
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionItem.css b/src/core/client/admin/App/DecisionHistory/DecisionItem.css
index ceb23e4be..de4a66b9f 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionItem.css
+++ b/src/core/client/admin/App/DecisionHistory/DecisionItem.css
@@ -1,6 +1,5 @@
.root {
- padding: calc(0.5 * var(--mini-unit)) calc(0.5 * var(--mini-unit))
- calc(0.5 * var(--mini-unit)) 0;
+ padding: var(--v2-spacing-2) var(--v2-spacing-1);
}
.leftCol {
@@ -8,6 +7,6 @@
justify-content: center;
flex-grow: 0;
flex-shrink: 0;
- width: calc(3 * var(--mini-unit));
padding-top: 3px;
+ margin-right: var(--v2-spacing-2);
}
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionItem.tsx b/src/core/client/admin/App/DecisionHistory/DecisionItem.tsx
index 562e2da39..04476663c 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionItem.tsx
+++ b/src/core/client/admin/App/DecisionHistory/DecisionItem.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { Flex } from "coral-ui/components";
+import { Flex } from "coral-ui/components/v2";
import styles from "./DecisionItem.css";
diff --git a/src/core/client/admin/App/DecisionHistory/DecisionList.css b/src/core/client/admin/App/DecisionHistory/DecisionList.css
index 92219280f..388876150 100644
--- a/src/core/client/admin/App/DecisionHistory/DecisionList.css
+++ b/src/core/client/admin/App/DecisionHistory/DecisionList.css
@@ -4,7 +4,7 @@
list-style-type: none;
& > * {
- border-bottom: 1px solid var(--palette-divider);
+ border-bottom: 1px solid var(--v2-palette-decision-history-border);
}
& > *:last-child {
border-bottom: 0;
diff --git a/src/core/client/admin/App/DecisionHistory/DotDivider.css b/src/core/client/admin/App/DecisionHistory/DotDivider.css
index 8df5fc9aa..090adbdbb 100644
--- a/src/core/client/admin/App/DecisionHistory/DotDivider.css
+++ b/src/core/client/admin/App/DecisionHistory/DotDivider.css
@@ -1,7 +1,7 @@
.root {
height: 100%;
- font-size: calc(12rem / var(--rem-base));
- line-height: calc(12em / 12);
- color: var(--palette-divider);
- padding: 0 calc(0.5 * var(--mini-unit));
+ font-size: var(--v2-font-size-1);
+ line-height: var(--v2-line-height-reset);
+ color: var(--v2-palette-timestamp);
+ padding: 0 var(--v2-spacing-1);
}
diff --git a/src/core/client/admin/App/DecisionHistory/Empty.css b/src/core/client/admin/App/DecisionHistory/Empty.css
index e50019701..79dc92187 100644
--- a/src/core/client/admin/App/DecisionHistory/Empty.css
+++ b/src/core/client/admin/App/DecisionHistory/Empty.css
@@ -1,3 +1,10 @@
.root {
padding: calc(1.5 * var(--mini-unit)) calc(2 * var(--mini-unit));
}
+
+.text {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-body-short);
+}
diff --git a/src/core/client/admin/App/DecisionHistory/Empty.tsx b/src/core/client/admin/App/DecisionHistory/Empty.tsx
index 1c3b83a98..d88e7e268 100644
--- a/src/core/client/admin/App/DecisionHistory/Empty.tsx
+++ b/src/core/client/admin/App/DecisionHistory/Empty.tsx
@@ -1,16 +1,16 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Flex, Typography } from "coral-ui/components";
+import { Flex } from "coral-ui/components/v2";
import styles from "./Empty.css";
const Empty: FunctionComponent<{}> = () => (
-
+
You will see a list of your post moderation actions here.
-
+
);
diff --git a/src/core/client/admin/App/DecisionHistory/Footer.css b/src/core/client/admin/App/DecisionHistory/Footer.css
index c3a2af639..0dbf825ea 100644
--- a/src/core/client/admin/App/DecisionHistory/Footer.css
+++ b/src/core/client/admin/App/DecisionHistory/Footer.css
@@ -1,2 +1,3 @@
.root {
+ margin-top: var(--v2-spacing-1);
}
diff --git a/src/core/client/admin/App/DecisionHistory/Footer.tsx b/src/core/client/admin/App/DecisionHistory/Footer.tsx
index c1e50a899..a83a1f2d6 100644
--- a/src/core/client/admin/App/DecisionHistory/Footer.tsx
+++ b/src/core/client/admin/App/DecisionHistory/Footer.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { Flex } from "coral-ui/components";
+import { Flex } from "coral-ui/components/v2";
import styles from "./Footer.css";
diff --git a/src/core/client/admin/App/DecisionHistory/GoToCommentLink.css b/src/core/client/admin/App/DecisionHistory/GoToCommentLink.css
index 519ed50fb..38e560e48 100644
--- a/src/core/client/admin/App/DecisionHistory/GoToCommentLink.css
+++ b/src/core/client/admin/App/DecisionHistory/GoToCommentLink.css
@@ -1,9 +1,8 @@
.root {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
- line-height: calc(14em / 12);
- letter-spacing: calc(0.2em / 12);
- color: var(--palette-primary-main);
- text-decoration: none;
+ line-height: var(--v2-line-height-reset);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-family: var(--v2-font-family-primary);
+ font-size: var(--v2-font-size-1);
+ color: var(--v2-palette-link-text);
+ font-style: var(--v2-font-style-underline);
}
diff --git a/src/core/client/admin/App/DecisionHistory/GoToCommentLink.tsx b/src/core/client/admin/App/DecisionHistory/GoToCommentLink.tsx
index edb689e99..aeed3bac1 100644
--- a/src/core/client/admin/App/DecisionHistory/GoToCommentLink.tsx
+++ b/src/core/client/admin/App/DecisionHistory/GoToCommentLink.tsx
@@ -2,7 +2,7 @@ import { Localized } from "fluent-react/compat";
import { Link } from "found";
import React, { FunctionComponent } from "react";
-import { Icon, TextLink } from "coral-ui/components";
+import { Icon, TextLink } from "coral-ui/components/v2";
import styles from "./GoToCommentLink.css";
diff --git a/src/core/client/admin/App/DecisionHistory/Info.css b/src/core/client/admin/App/DecisionHistory/Info.css
index daa3c0e8f..942637a82 100644
--- a/src/core/client/admin/App/DecisionHistory/Info.css
+++ b/src/core/client/admin/App/DecisionHistory/Info.css
@@ -1,6 +1,4 @@
.root {
- font-size: calc(14rem / var(--rem-base));
- line-height: calc(16em / 12);
/*
Fallback begin
@@ -10,4 +8,9 @@
word-break: break-all;
/* Fallback end */
word-break: break-word;
+ color: var(--v2-palette-text-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-body-short);
+ font-size: var(--v2-font-size-2);
}
diff --git a/src/core/client/admin/App/DecisionHistory/Info.tsx b/src/core/client/admin/App/DecisionHistory/Info.tsx
index 452eda05f..d4832915f 100644
--- a/src/core/client/admin/App/DecisionHistory/Info.tsx
+++ b/src/core/client/admin/App/DecisionHistory/Info.tsx
@@ -1,7 +1,5 @@
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import styles from "./Info.css";
interface Props {
@@ -9,7 +7,7 @@ interface Props {
}
const Info: FunctionComponent = props => (
- {props.children}
+ {props.children}
);
export default Info;
diff --git a/src/core/client/admin/App/DecisionHistory/RejectedComment.tsx b/src/core/client/admin/App/DecisionHistory/RejectedComment.tsx
index 017698356..f2fc6f6c8 100644
--- a/src/core/client/admin/App/DecisionHistory/RejectedComment.tsx
+++ b/src/core/client/admin/App/DecisionHistory/RejectedComment.tsx
@@ -1,8 +1,6 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import DecisionItem from "./DecisionItem";
import DotDivider from "./DotDivider";
import Footer from "./Footer";
@@ -10,6 +8,7 @@ import GoToCommentLink from "./GoToCommentLink";
import Info from "./Info";
import RejectedIcon from "./RejectedIcon";
import Timestamp from "./Timestamp";
+import Username from "./Username";
interface Props {
href: string;
@@ -18,10 +17,6 @@ interface Props {
onGotoComment?: React.EventHandler;
}
-const Username: FunctionComponent<{ username: string }> = ({ username }) => (
- {username}
-);
-
const RejectedComment: FunctionComponent = props => (
}>
= props => (
{"Rejected comment by "}
-
- {props.date}
-
+ {props.date}
diff --git a/src/core/client/admin/App/DecisionHistory/RejectedIcon.css b/src/core/client/admin/App/DecisionHistory/RejectedIcon.css
index 488befa65..c5bddba45 100644
--- a/src/core/client/admin/App/DecisionHistory/RejectedIcon.css
+++ b/src/core/client/admin/App/DecisionHistory/RejectedIcon.css
@@ -1,3 +1,3 @@
.root {
- color: var(--palette-error-main);
+ color: var(--v2-palette-error-main);
}
diff --git a/src/core/client/admin/App/DecisionHistory/RejectedIcon.tsx b/src/core/client/admin/App/DecisionHistory/RejectedIcon.tsx
index 1dde0162f..38f0818f5 100644
--- a/src/core/client/admin/App/DecisionHistory/RejectedIcon.tsx
+++ b/src/core/client/admin/App/DecisionHistory/RejectedIcon.tsx
@@ -1,11 +1,13 @@
import React, { FunctionComponent } from "react";
-import { Icon } from "coral-ui/components";
+import { Icon } from "coral-ui/components/v2";
import styles from "./RejectedIcon.css";
const RejectedIcon: FunctionComponent = () => (
- cancel
+
+ cancel
+
);
export default RejectedIcon;
diff --git a/src/core/client/admin/App/DecisionHistory/ShowMoreButton.css b/src/core/client/admin/App/DecisionHistory/ShowMoreButton.css
index 87c94f276..81935a4d1 100644
--- a/src/core/client/admin/App/DecisionHistory/ShowMoreButton.css
+++ b/src/core/client/admin/App/DecisionHistory/ShowMoreButton.css
@@ -1,16 +1,17 @@
.root {
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
text-transform: uppercase;
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(2 * var(--mini-unit));
- letter-spacing: calc(0.2em / 12);
- color: var(--palette-grey-main);
+ color: var(--v2-palette-link-text);
width: 100%;
- border-top: 1px solid var(--palette-divider);
+ border-top: 1px solid var(--v2-palette-decision-history-border);
text-align: center;
+ padding-top: var(--v2-spacing-1);
+ padding-bottom: var(--v2-spacing-1);
&:disabled {
- color: var(--palette-grey-lighter);
+ color: var(--v2-palette-grey-lighter);
}
}
diff --git a/src/core/client/admin/App/DecisionHistory/ShowMoreButton.tsx b/src/core/client/admin/App/DecisionHistory/ShowMoreButton.tsx
index 4cdf8bc7e..646244f57 100644
--- a/src/core/client/admin/App/DecisionHistory/ShowMoreButton.tsx
+++ b/src/core/client/admin/App/DecisionHistory/ShowMoreButton.tsx
@@ -1,7 +1,7 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { BaseButton } from "coral-ui/components";
+import { BaseButton } from "coral-ui/components/v2";
import styles from "./ShowMoreButton.css";
diff --git a/src/core/client/admin/App/DecisionHistory/Timestamp.css b/src/core/client/admin/App/DecisionHistory/Timestamp.css
index 45c88b4cf..1035d2ee9 100644
--- a/src/core/client/admin/App/DecisionHistory/Timestamp.css
+++ b/src/core/client/admin/App/DecisionHistory/Timestamp.css
@@ -1,8 +1,7 @@
.root {
- color: var(--palette-text-secondary);
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-medium);
- font-size: calc(12rem / var(--rem-base));
- line-height: calc(14em / 12);
- letter-spacing: 0;
+ color: var(--v2-palette-timestamp);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-1);
+ line-height: var(--v2-line-height-reset);
}
diff --git a/src/core/client/admin/App/DecisionHistory/Timestamp.tsx b/src/core/client/admin/App/DecisionHistory/Timestamp.tsx
index 881e41ca8..a476021e8 100644
--- a/src/core/client/admin/App/DecisionHistory/Timestamp.tsx
+++ b/src/core/client/admin/App/DecisionHistory/Timestamp.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { RelativeTime } from "coral-ui/components";
+import { RelativeTime } from "coral-ui/components/v2";
import styles from "./Timestamp.css";
diff --git a/src/core/client/admin/App/DecisionHistory/Title.css b/src/core/client/admin/App/DecisionHistory/Title.css
index 48e9ebba3..abe310699 100644
--- a/src/core/client/admin/App/DecisionHistory/Title.css
+++ b/src/core/client/admin/App/DecisionHistory/Title.css
@@ -1,16 +1,20 @@
.root {
- padding: 0 calc(0.5 * var(--mini-unit));
- background-color: #f2f2f2;
- color: var(--palette-text-primary);
- border-bottom: 1px solid var(--palette-grey-lighter);
+ background: var(--v2-palette-decision-history-title-background);
+ padding: var(--v2-spacing-1);
+ color: var(--v2-palette-text-primary);
+ border-bottom: 1px solid var(--v2-palette-decision-history-border);
+ font-size: var(--v2-font-size-icon-medium);
+}
+
+.icon {
+ margin-right: var(--v2-spacing-2);
}
.text {
text-transform: uppercase;
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(12em / 12);
- letter-spacing: calc(0.2em / 12);
- color: var(--palette-text-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ color: var(--v2-palette-text-primary);
+ font-size: var(--v2-font-size-2);
+ line-height: 1;
+ font-family: var(--v2-font-family-primary);
}
diff --git a/src/core/client/admin/App/DecisionHistory/Title.tsx b/src/core/client/admin/App/DecisionHistory/Title.tsx
index d56a34daf..f72cfc295 100644
--- a/src/core/client/admin/App/DecisionHistory/Title.tsx
+++ b/src/core/client/admin/App/DecisionHistory/Title.tsx
@@ -1,17 +1,17 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Flex, Icon, Typography } from "coral-ui/components";
+import { Flex, Icon } from "coral-ui/components/v2";
import styles from "./Title.css";
const Title: FunctionComponent = () => (
- history {" "}
+
+ history
+
-
- Your Decision History
-
+ Your Decision History
);
diff --git a/src/core/client/admin/App/DecisionHistory/Username.css b/src/core/client/admin/App/DecisionHistory/Username.css
new file mode 100644
index 000000000..fa7603d5d
--- /dev/null
+++ b/src/core/client/admin/App/DecisionHistory/Username.css
@@ -0,0 +1,7 @@
+.root {
+ color: var(--v2-palette-username-emphasis);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-family: var(--v2-font-family-secondary);
+ line-height: var(--v2-line-height-body-short);
+ font-size: var(--v2-font-size-3);
+}
diff --git a/src/core/client/admin/App/DecisionHistory/Username.tsx b/src/core/client/admin/App/DecisionHistory/Username.tsx
new file mode 100644
index 000000000..9e98a5839
--- /dev/null
+++ b/src/core/client/admin/App/DecisionHistory/Username.tsx
@@ -0,0 +1,13 @@
+import React, { FunctionComponent } from "react";
+
+import styles from "./Username.css";
+
+interface Props {
+ username: string;
+}
+
+const Username: FunctionComponent = ({ username }) => (
+ {username}
+);
+
+export default Username;
diff --git a/src/core/client/admin/App/DecisionHistory/__snapshots__/ApprovedComment.spec.tsx.snap b/src/core/client/admin/App/DecisionHistory/__snapshots__/ApprovedComment.spec.tsx.snap
index 41e70e055..bcd6da0b9 100644
--- a/src/core/client/admin/App/DecisionHistory/__snapshots__/ApprovedComment.spec.tsx.snap
+++ b/src/core/client/admin/App/DecisionHistory/__snapshots__/ApprovedComment.spec.tsx.snap
@@ -17,13 +17,9 @@ exports[`renders correctly 1`] = `
-
-
- 2018-07-06T18:24:00.000Z
-
-
+
+ 2018-07-06T18:24:00.000Z
+
- check
+ check_circled
`;
diff --git a/src/core/client/admin/App/DecisionHistory/__snapshots__/Empty.spec.tsx.snap b/src/core/client/admin/App/DecisionHistory/__snapshots__/Empty.spec.tsx.snap
index 37fe9cb3c..c0c373140 100644
--- a/src/core/client/admin/App/DecisionHistory/__snapshots__/Empty.spec.tsx.snap
+++ b/src/core/client/admin/App/DecisionHistory/__snapshots__/Empty.spec.tsx.snap
@@ -9,9 +9,11 @@ exports[`renders correctly 1`] = `
-
+
You will see a list of your post moderation actions here.
-
+
`;
diff --git a/src/core/client/admin/App/DecisionHistory/__snapshots__/Info.spec.tsx.snap b/src/core/client/admin/App/DecisionHistory/__snapshots__/Info.spec.tsx.snap
index 74ef09e04..d9c3b286c 100644
--- a/src/core/client/admin/App/DecisionHistory/__snapshots__/Info.spec.tsx.snap
+++ b/src/core/client/admin/App/DecisionHistory/__snapshots__/Info.spec.tsx.snap
@@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
-
children
-
+
`;
diff --git a/src/core/client/admin/App/DecisionHistory/__snapshots__/RejectedComment.spec.tsx.snap b/src/core/client/admin/App/DecisionHistory/__snapshots__/RejectedComment.spec.tsx.snap
index 7bed59997..2e1bd35f2 100644
--- a/src/core/client/admin/App/DecisionHistory/__snapshots__/RejectedComment.spec.tsx.snap
+++ b/src/core/client/admin/App/DecisionHistory/__snapshots__/RejectedComment.spec.tsx.snap
@@ -17,13 +17,9 @@ exports[`renders correctly 1`] = `
-
-
- 2018-07-06T18:24:00.000Z
-
-
+
+ 2018-07-06T18:24:00.000Z
+
cancel
diff --git a/src/core/client/admin/App/DecisionHistory/__snapshots__/Title.spec.tsx.snap b/src/core/client/admin/App/DecisionHistory/__snapshots__/Title.spec.tsx.snap
index 9670cf1dd..3a0b23ed5 100644
--- a/src/core/client/admin/App/DecisionHistory/__snapshots__/Title.spec.tsx.snap
+++ b/src/core/client/admin/App/DecisionHistory/__snapshots__/Title.spec.tsx.snap
@@ -5,19 +5,20 @@ exports[`renders correctly 1`] = `
alignItems="center"
className="Title-root"
>
-
+
history
-
-
Your Decision History
-
+
`;
diff --git a/src/core/client/admin/App/Main.tsx b/src/core/client/admin/App/Main.tsx
index fa2ba2a5d..28cd1a922 100644
--- a/src/core/client/admin/App/Main.tsx
+++ b/src/core/client/admin/App/Main.tsx
@@ -2,7 +2,7 @@ import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
import { LogoHorizontal } from "coral-ui/components";
-import { AppBar, Begin, Divider, End } from "coral-ui/components/AppBar";
+import { AppBar, Begin, Divider, End } from "coral-ui/components/v2/AppBar";
import { DecisionHistoryButton } from "./DecisionHistory";
import NavigationContainer from "./Navigation";
diff --git a/src/core/client/admin/App/Navigation/Navigation.tsx b/src/core/client/admin/App/Navigation/Navigation.tsx
index 0a8de2169..c53f5e0f3 100644
--- a/src/core/client/admin/App/Navigation/Navigation.tsx
+++ b/src/core/client/admin/App/Navigation/Navigation.tsx
@@ -1,7 +1,7 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { AppBarNavigation } from "coral-ui/components";
+import { AppBarNavigation } from "coral-ui/components/v2";
import NavigationLink from "./NavigationLink";
diff --git a/src/core/client/admin/App/Navigation/NavigationLink.tsx b/src/core/client/admin/App/Navigation/NavigationLink.tsx
index daa9b4026..8057f862e 100644
--- a/src/core/client/admin/App/Navigation/NavigationLink.tsx
+++ b/src/core/client/admin/App/Navigation/NavigationLink.tsx
@@ -1,7 +1,7 @@
import { Link, LocationDescriptor } from "found";
import React, { FunctionComponent } from "react";
-import { AppBarNavigationItem } from "coral-ui/components";
+import { AppBarNavigationItem } from "coral-ui/components/v2";
interface Props {
children: React.ReactNode;
diff --git a/src/core/client/admin/App/UserMenu/UserMenu.css b/src/core/client/admin/App/UserMenu/UserMenu.css
index 278978da0..42f0848f1 100644
--- a/src/core/client/admin/App/UserMenu/UserMenu.css
+++ b/src/core/client/admin/App/UserMenu/UserMenu.css
@@ -1,11 +1,17 @@
.button {
padding-top: 0;
padding-bottom: 0;
- margin-left: 5px;
+ margin-left: 15px;
}
+
+.icon {
+ color: var(--v2-palette-user-menu-button);
+}
+
.buttonText {
- font-size: calc(18rem / var(--rem-base));
- letter-spacing: calc(-0.2em / 18);
+ font-family: var(--v2-font-family-secondary);
+ color: var(--v2-palette-user-menu-button);
+ font-size: var(--v2-font-size-4);
margin-left: 2px;
margin-right: 1px;
}
diff --git a/src/core/client/admin/App/UserMenu/UserMenu.tsx b/src/core/client/admin/App/UserMenu/UserMenu.tsx
index 462ec283e..3499b0b85 100644
--- a/src/core/client/admin/App/UserMenu/UserMenu.tsx
+++ b/src/core/client/admin/App/UserMenu/UserMenu.tsx
@@ -9,7 +9,7 @@ import {
DropdownButton,
DropdownDivider,
Popover,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import styles from "./UserMenu.css";
@@ -60,13 +60,16 @@ const UserMenu: FunctionComponent = props => (
className={styles.button}
onClick={toggleVisibility}
ref={ref}
- variant="regular"
+ variant="plain"
+ uppercase={false}
size="small"
>
- account_circle
+
+ account_circle
+
{props.username}
{
-
+
{visible ? "arrow_drop_up" : "arrow_drop_down"}
}
diff --git a/src/core/client/admin/components/AutoLoadMore.tsx b/src/core/client/admin/components/AutoLoadMore.tsx
index 86cb1f6a9..9c429e431 100644
--- a/src/core/client/admin/components/AutoLoadMore.tsx
+++ b/src/core/client/admin/components/AutoLoadMore.tsx
@@ -1,7 +1,7 @@
import React from "react";
import { withInView } from "coral-framework/lib/intersection";
-import { BaseButton, Spinner } from "coral-ui/components";
+import { BaseButton, Spinner } from "coral-ui/components/v2";
interface Props {
inView: boolean | undefined;
diff --git a/src/core/client/admin/components/ModerateCard/ApproveButton.css b/src/core/client/admin/components/ModerateCard/ApproveButton.css
index cf2ff389b..b01f55290 100644
--- a/src/core/client/admin/components/ModerateCard/ApproveButton.css
+++ b/src/core/client/admin/components/ModerateCard/ApproveButton.css
@@ -1,25 +1,25 @@
.root {
- border: 1px solid var(--palette-success-main);
+ border: 1px solid var(--v2-palette-button-outline-approve);
box-sizing: border-box;
- border-radius: var(--round-corners);
+ border-radius: var(--v2-round-corners);
width: 65px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
- color: var(--palette-success-main);
+ color: var(--v2-palette-button-outline-approve);
&:not(:disabled):active {
- background-color: var(--palette-success-main);
- color: var(--palette-common-white);
+ background-color: var(--v2-palette-button-outline-approve);
+ color: var(--v2-colors-pure-white);
}
}
.invert {
- background-color: var(--palette-success-main);
- color: var(--palette-common-white);
+ background-color: var(--v2-palette-button-outline-approve);
+ color: var(--v2-colors-pure-white);
}
.icon {
- font-weight: var(--font-weight-bold);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
color: inherit;
}
diff --git a/src/core/client/admin/components/ModerateCard/ApproveButton.tsx b/src/core/client/admin/components/ModerateCard/ApproveButton.tsx
index 8be2ef2ac..6c38a52c1 100644
--- a/src/core/client/admin/components/ModerateCard/ApproveButton.tsx
+++ b/src/core/client/admin/components/ModerateCard/ApproveButton.tsx
@@ -3,7 +3,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { BaseButton, Icon } from "coral-ui/components";
+import { BaseButton, Icon } from "coral-ui/components/v2";
import styles from "./ApproveButton.css";
diff --git a/src/core/client/admin/components/ModerateCard/BanCommentUserMutation.ts b/src/core/client/admin/components/ModerateCard/BanCommentUserMutation.ts
index fe4858f15..b10d78a06 100644
--- a/src/core/client/admin/components/ModerateCard/BanCommentUserMutation.ts
+++ b/src/core/client/admin/components/ModerateCard/BanCommentUserMutation.ts
@@ -1,13 +1,14 @@
import { graphql } from "react-relay";
import { Environment } from "relay-runtime";
-import { BanCommentUserMutation as MutationTypes } from "coral-admin/__generated__/BanCommentUserMutation.graphql";
import {
commitMutationPromiseNormalized,
createMutation,
MutationInput,
} from "coral-framework/lib/relay";
+import { BanCommentUserMutation as MutationTypes } from "coral-admin/__generated__/BanCommentUserMutation.graphql";
+
const clientMutationId = 0;
const BanCommentUserMutation = createMutation(
diff --git a/src/core/client/admin/components/ModerateCard/CommentAuthorContainer.tsx b/src/core/client/admin/components/ModerateCard/CommentAuthorContainer.tsx
index 98aaf0ee1..ba07eeb43 100644
--- a/src/core/client/admin/components/ModerateCard/CommentAuthorContainer.tsx
+++ b/src/core/client/admin/components/ModerateCard/CommentAuthorContainer.tsx
@@ -1,9 +1,10 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { CommentAuthorContainer_comment as CommentData } from "coral-admin/__generated__/CommentAuthorContainer_comment.graphql";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
-import { Tag } from "coral-ui/components";
+import { Tag } from "coral-ui/components/v2";
+
+import { CommentAuthorContainer_comment as CommentData } from "coral-admin/__generated__/CommentAuthorContainer_comment.graphql";
import styles from "./CommentAuthorContainer.css";
diff --git a/src/core/client/admin/components/ModerateCard/CommentContent.css b/src/core/client/admin/components/ModerateCard/CommentContent.css
index 0d59c0902..285d85278 100644
--- a/src/core/client/admin/components/ModerateCard/CommentContent.css
+++ b/src/core/client/admin/components/ModerateCard/CommentContent.css
@@ -1,13 +1,52 @@
+$comment-content: var(--v2-colors-mono-900);
+$comment-blockquote-bg: var(--v2-colors-grey-100);
+$comment-highlight-bg: var(--v2-colors-yellow-500);
+$comment-link: var(--v2-palette-primary-main);
+$comment-link-active: var(--v2-palette-primary-darkest);
+
.root {
- composes: root from "coral-stream/shared/htmlContent.css";
+ composes: bodyCommentV2 from "coral-ui/shared/typography.css";
+ font-family: var(--v2-font-family-primary);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-body-comment);
+ color: $comment-content;
+ overflow-wrap: break-word;
+
+ & * bold,
+ & * strong {
+ font-weight: var(--v2-font-weight-primary-bold);
+ }
+ & * italic,
+ & * em {
+ font-style: italic;
+ }
+ blockquote {
+ background-color: $comment-blockquote-bg;
+ padding: var(--mini-unit);
+ margin: calc(2 * var(--mini-unit)) 0 calc(2 * var(--mini-unit))
+ var(--mini-unit);
+ border-radius: var(--round-corners);
+ &::after {
+ content: none;
+ }
+ &::before {
+ content: none;
+ }
+ }
mark {
- background-color: var(--palette-highlight);
+ background-color: $comment-highlight-bg;
padding: 0 2px;
+ a {
+ color: $comment-link;
+ }
}
a {
- color: var(--palette-primary-dark);
- background-color: var(--palette-highlight);
+ color: $comment-link;
+ background-color: $comment-highlight-bg;
padding: 0 2px;
+ &:hover {
+ color: $comment-link-active;
+ }
}
}
diff --git a/src/core/client/admin/components/ModerateCard/CommentContent.tsx b/src/core/client/admin/components/ModerateCard/CommentContent.tsx
index 0b878e747..252e546de 100644
--- a/src/core/client/admin/components/ModerateCard/CommentContent.tsx
+++ b/src/core/client/admin/components/ModerateCard/CommentContent.tsx
@@ -3,7 +3,6 @@ import { memoize } from "lodash";
import React, { FunctionComponent } from "react";
import { createPurify } from "coral-common/utils/purify";
-import { Typography } from "coral-ui/components";
import styles from "./CommentContent.css";
@@ -131,10 +130,9 @@ const CommentContent: FunctionComponent = ({
// Finally we render the content of the Shadow DOM Tree
return (
-
);
}
diff --git a/src/core/client/admin/components/ModerateCard/CommentRevisionContainer.tsx b/src/core/client/admin/components/ModerateCard/CommentRevisionContainer.tsx
index 1dadd742e..9a3c6fd31 100644
--- a/src/core/client/admin/components/ModerateCard/CommentRevisionContainer.tsx
+++ b/src/core/client/admin/components/ModerateCard/CommentRevisionContainer.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
-import { HorizontalGutter, Timestamp } from "coral-ui/components";
+import { HorizontalGutter, Timestamp } from "coral-ui/components/v2";
import { CommentRevisionContainer_comment as CommentData } from "coral-admin/__generated__/CommentRevisionContainer_comment.graphql";
import { CommentRevisionContainer_settings as SettingsData } from "coral-admin/__generated__/CommentRevisionContainer_settings.graphql";
diff --git a/src/core/client/admin/components/ModerateCard/FeatureButton.css b/src/core/client/admin/components/ModerateCard/FeatureButton.css
index 5fbeb7ecb..0166dd6f0 100644
--- a/src/core/client/admin/components/ModerateCard/FeatureButton.css
+++ b/src/core/client/admin/components/ModerateCard/FeatureButton.css
@@ -3,7 +3,7 @@
right: 0px;
top: 2px;
- border: 1px solid var(--palette-grey-lighter);
+ border: 1px solid var(--v2-palette-grey-main);
box-sizing: border-box;
border-radius: var(--round-corners);
padding: 2px var(--spacing-2) 2px var(--spacing-2);
@@ -11,22 +11,21 @@
justify-content: center;
align-items: center;
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
+ color: var(--v2-palette-grey-main);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
line-height: 1.2;
- letter-spacing: calc(0.2em / 14);
- color: var(--palette-grey-lighter);
-
+
&:active {
- background-color: var(--palette-primary-lightest);
- border-color: var(--palette-primary-main);
- color: var(--palette-primary-main);
+ background-color: var(--v2-palette-primary-lightest);
+ border-color: var(--v2-palette-primary-main);
+ color: var(--v2-palette-primary-main);
}
}
.invert {
- background-color: var(--palette-primary-main);
- border-color: var(--palette-primary-main);
- color: var(--palette-text-light) ;
-}
\ No newline at end of file
+ background-color: var(--v2-palette-primary-main);
+ border-color: var(--v2-palette-primary-main);
+ color: var(--v2-palette-text-light);
+}
diff --git a/src/core/client/admin/components/ModerateCard/FeatureButton.tsx b/src/core/client/admin/components/ModerateCard/FeatureButton.tsx
index 55f7472a4..fb826bd75 100644
--- a/src/core/client/admin/components/ModerateCard/FeatureButton.tsx
+++ b/src/core/client/admin/components/ModerateCard/FeatureButton.tsx
@@ -3,7 +3,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { BaseButton } from "coral-ui/components";
+import { BaseButton } from "coral-ui/components/v2";
import styles from "./FeatureButton.css";
diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css
index 3ce9c004c..395d5eab6 100644
--- a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css
+++ b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.css
@@ -1,3 +1,7 @@
.category {
- color: var(--palette-error-darkest);
+ font-size: var(--v2-font-size-4);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-body-short);
+ color: var(--v2-palette-accordion-label);
}
diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.tsx b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.tsx
index 8f8d58ed9..08d7fc590 100644
--- a/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.tsx
+++ b/src/core/client/admin/components/ModerateCard/FlagDetailsCategory.tsx
@@ -1,6 +1,8 @@
import React, { FunctionComponent } from "react";
-import { HorizontalGutter, Typography } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
+
+import styles from "./FlagDetailsCategory.css";
interface Props {
category: React.ReactNode;
@@ -13,7 +15,7 @@ const FlagDetailsCategory: FunctionComponent = ({
}) => {
return (
- {category}
+ {category}
{children}
);
diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx
index 60a782f54..e35b432d9 100644
--- a/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx
+++ b/src/core/client/admin/components/ModerateCard/FlagDetailsContainer.tsx
@@ -6,7 +6,7 @@ import NotAvailable from "coral-admin/components/NotAvailable";
import { TOXICITY_THRESHOLD_DEFAULT } from "coral-common/constants";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { GQLCOMMENT_FLAG_REASON } from "coral-framework/schema";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import { FlagDetailsContainer_comment } from "coral-admin/__generated__/FlagDetailsContainer_comment.graphql";
import { FlagDetailsContainer_settings } from "coral-admin/__generated__/FlagDetailsContainer_settings.graphql";
diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css
index 21ca38fb3..76217b736 100644
--- a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css
+++ b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.css
@@ -1,37 +1,35 @@
.user {
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-serif);
- line-height: calc(16em / 14);
- letter-spacing: calc(0.2em / 14);
- color: var(--palette-text-primary);
+ color: var(--v2-palette-username-emphasis);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-family: var(--v2-font-family-secondary);
+ line-height: var(--v2-line-height-title);
padding-right: calc(0.5 * var(--mini-unit));
}
+
.details {
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
- line-height: calc(16em / 14);
- letter-spacing: calc(0.2em / 14);
- color: var(--palette-text-primary);
- font-style: italic;
+ color: var(--v2-palette-reason-text);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-title);
}
.flagger {
+ line-height: var(--v2-line-height-reset);
margin-right: var(--mini-unit);
- padding: var(--spacing-1);
- margin-left: calc(-1 * var(--spacing-1));
- line-height: calc(16rem / var(--rem-base));
+ padding: var(--v2-spacing-1);
+ margin-left: calc(-1 * var(--v2-spacing-1));
&:hover {
- background-color: var(--palette-grey-lightest);
- border-radius: var(--round-corners);
+ background-color: var(--v2-palette-grey-lightest);
+ border-radius: var(--v2-round-corners);
border-style: none;
}
&:active {
- background-color: var(--palette-grey-lighter);
- border-radius: var(--round-corners);
+ background-color: var(--v2-palette-grey-lighter);
+ border-radius: var(--v2-round-corners);
border-style: none;
}
-}
\ No newline at end of file
+}
diff --git a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx
index e4bc62788..0063feee8 100644
--- a/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx
+++ b/src/core/client/admin/components/ModerateCard/FlagDetailsEntry.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { BaseButton } from "coral-ui/components";
+import { BaseButton } from "coral-ui/components/v2";
import styles from "./FlagDetailsEntry.css";
diff --git a/src/core/client/admin/components/ModerateCard/InReplyTo.css b/src/core/client/admin/components/ModerateCard/InReplyTo.css
index bd62abb8c..7fe840a16 100644
--- a/src/core/client/admin/components/ModerateCard/InReplyTo.css
+++ b/src/core/client/admin/components/ModerateCard/InReplyTo.css
@@ -1,13 +1,37 @@
.icon {
- color: var(--palette-grey-main);
+ color: var(--v2-palette-label-regular);
}
.inReplyTo {
- color: var(--palette-grey-main);
+ color: var(--v2-palette-label-regular);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-reset);
}
.username {
- color: var(--palette-grey-main);
+ color: var(--v2-palette-username-regular);
+ font-family: var(--v2-font-family-secondary);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
+
+ padding: var(--spacing-1);
+
+ &:hover {
+ background-color: var(--v2-palette-username-background-hover);
+ border-radius: var(--round-corners);
+ border-style: none;
+ }
+
+ &:active {
+ background-color: var(--v2-palette-username-background-hover);
+ border-radius: var(--round-corners);
+ border-style: none;
+ }
}
.usernameButton {
- display: inline-flex;
+ vertical-align: baseline;
+
+ margin-left: calc(-1 * var(--v2-spacing-1));
}
diff --git a/src/core/client/admin/components/ModerateCard/InReplyTo.spec.tsx b/src/core/client/admin/components/ModerateCard/InReplyTo.spec.tsx
index daeecc37f..194f542a2 100644
--- a/src/core/client/admin/components/ModerateCard/InReplyTo.spec.tsx
+++ b/src/core/client/admin/components/ModerateCard/InReplyTo.spec.tsx
@@ -8,6 +8,9 @@ import InReplyTo from "./InReplyTo";
it("renders correctly", () => {
const props: PropTypesOf = {
children: "Username",
+ onUsernameClick: () => {
+ return;
+ },
};
const renderer = createRenderer();
renderer.render( );
diff --git a/src/core/client/admin/components/ModerateCard/InReplyTo.tsx b/src/core/client/admin/components/ModerateCard/InReplyTo.tsx
index 5c7e29c10..428f8eaff 100644
--- a/src/core/client/admin/components/ModerateCard/InReplyTo.tsx
+++ b/src/core/client/admin/components/ModerateCard/InReplyTo.tsx
@@ -1,32 +1,30 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Flex, Icon, Typography } from "coral-ui/components";
+import { BaseButton, Flex, Icon } from "coral-ui/components/v2";
import styles from "./InReplyTo.css";
interface Props {
children: string;
+ onUsernameClick: () => void;
}
-const InReplyTo: FunctionComponent = ({ children }) => {
+const InReplyTo: FunctionComponent = ({ children, onUsernameClick }) => {
const Username = () => (
-
- {children}
-
+
+ {children}
+
);
return (
reply {" "}
}>
-
- {"Reply to "}
-
+
+ Reply to
+
+
);
diff --git a/src/core/client/admin/components/ModerateCard/Markers.css b/src/core/client/admin/components/ModerateCard/Markers.css
index 8f84cbe58..6946babd1 100644
--- a/src/core/client/admin/components/ModerateCard/Markers.css
+++ b/src/core/client/admin/components/ModerateCard/Markers.css
@@ -1,20 +1,25 @@
.detailsButton {
+ font-size: var(--v2-font-size-1);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ line-height: 1.28;
height: 100%;
padding: 2px 0px;
margin-left: var(--mini-unit);
- font-size: calc(12rem / var(--rem-base));
- letter-spacing: calc(-0.1em / 12);
+
align-self: flex-end;
text-transform: uppercase;
- &.detailsButtonColorRegular {
- color: var(--palette-text-primary);
- }
+}
+
+.detailsButtonColorRegular {
+ border-color: var(--v2-palette-details-header);
}
.detailsText {
+ color: var(--v2-palette-details-header);
margin: 0;
}
.detailsDivider {
- border-color: var(--palette-grey-lightest);
+ border-color: var(--v2-palette-details-divider);
}
diff --git a/src/core/client/admin/components/ModerateCard/Markers.tsx b/src/core/client/admin/components/ModerateCard/Markers.tsx
index 89a6c2b0b..747b6ebae 100644
--- a/src/core/client/admin/components/ModerateCard/Markers.tsx
+++ b/src/core/client/admin/components/ModerateCard/Markers.tsx
@@ -2,7 +2,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useCallback, useState } from "react";
import { useUUID } from "coral-framework/hooks";
-import { Button, Flex, HorizontalGutter, Icon } from "coral-ui/components";
+import { Button, Flex, HorizontalGutter, Icon } from "coral-ui/components/v2";
import styles from "./Markers.css";
@@ -25,8 +25,8 @@ const Markers: FunctionComponent = ({ children, details }) => {
(c.status === "PREMOD" && (
- Pre-mod
+ Pre-Mod
)) ||
null,
@@ -40,7 +40,7 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_LINKS && (
- Link
+ Link
)) ||
null,
@@ -48,7 +48,7 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_BANNED_WORD && (
- Banned word
+ Banned Word
)) ||
null,
@@ -56,8 +56,8 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_SUSPECT_WORD && (
-
- Suspect word
+
+ Suspect Word
)) ||
@@ -66,7 +66,7 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_SPAM && (
- Spam detected
+ Spam Detected
)) ||
null,
@@ -74,7 +74,7 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_TOXIC && (
- Toxic
+ Toxic
)) ||
null,
@@ -82,7 +82,7 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_REPEAT_POST && (
- Repeat comment
+ Repeat comment
)) ||
null,
@@ -90,14 +90,14 @@ const markers: Array<
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_DETECTED_RECENT_HISTORY && (
- Recent history
+ Recent History
)) ||
null,
c =>
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_OFFENSIVE && (
-
+
Offensive
{" "}
@@ -110,7 +110,7 @@ const markers: Array<
c =>
(c.revision &&
c.revision.actionCounts.flag.reasons.COMMENT_REPORTED_SPAM && (
-
+
Spam
{" "}
diff --git a/src/core/client/admin/components/ModerateCard/ModerateCard.css b/src/core/client/admin/components/ModerateCard/ModerateCard.css
index 9ffff678f..96fea8824 100644
--- a/src/core/client/admin/components/ModerateCard/ModerateCard.css
+++ b/src/core/client/admin/components/ModerateCard/ModerateCard.css
@@ -1,41 +1,51 @@
.topBar {
position: relative;
- margin-bottom: var(--mini-unit);
+ margin-bottom: var(--v2-spacing-1);
}
.topBarMini {
- margin-bottom: var(--spacing-4);
+ margin-bottom: var(--v2-spacing-4);
}
-.username {
- margin-right: var(--spacing-1);
+.usernameButton {
+ margin-right: var(--mini-unit);
padding: var(--spacing-1);
- margin-left: calc(-1 * var(--spacing-1));
- line-height: calc(16rem / var(--rem-base));
+ margin-left: calc(-1 * var(--v2-spacing-1));
+
+ line-height: var(--v2-line-height-reset);
&:hover {
- background-color: var(--palette-grey-lightest);
- border-radius: var(--round-corners);
+ background-color: var(--v2-palette-username-background-hover);
+ border-radius: var(--v2-round-corners);
border-style: none;
}
&:active {
- background-color: var(--palette-grey-lighter);
- border-radius: var(--round-corners);
+ background-color: var(--v2-palette-username-background-hover);
+ border-radius: var(--v2-round-corners);
border-style: none;
}
}
+.inReplyTo {
+}
+
.footer {
margin-top: calc(2 * var(--mini-unit));
}
-.content {
- min-height: calc(5.5 * var(--mini-unit));
-}
-
.mainContainer {
flex-grow: 1;
+
+ margin-right: calc(2 * var(--v2-spacing-5));
+}
+
+.contentArea {
+ position: relative;
+}
+
+.content {
+ min-height: 3em;
}
.aside {
@@ -54,7 +64,7 @@
No reply to field, so we align below the fattest element
which is the feature button.
*/
- padding-top: calc((14rem / var(--rem-base)) + 7px + var(--spacing-4));
+ padding-top: calc(var(--v2-font-size-2) + 7px + var(--v2-spacing-4));
}
.asideMiniWithReplyTo {
@@ -62,27 +72,28 @@
We have reply to field, so we align below the fattest
element plus the reply to field.
*/
- padding-top: calc(2 * (14rem / var(--rem-base)) + 5px + var(--spacing-4));
+ padding-top: calc(2 * var(--v2-font-size-2) + 5px + var(--v2-spacing-4));
}
.decision {
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(16em / 14);
- letter-spacing: calc(0.2em / 14);
- color: var(--palette-text-primary);
+ color: var(--v2-palette-label-emphasis);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: 1.14;
text-transform: uppercase;
}
.separator {
- flex-shrink: 0;
- flex-grow: 0;
- margin: 0 calc(2 * var(--mini-unit));
+ position: absolute;
+ top: 0;
+ right: calc(-1 * var(--v2-spacing-5));
+ bottom: 0;
+ width: 2px;
}
.ruledSeparator {
- border-right: 1px solid var(--palette-divider);
+ border-right: 1px solid var(--v2-colors-grey-400);
}
.root {
@@ -94,62 +105,46 @@
}
.dangling {
- background-color: var(--palette-grey-lightest);
+ background-color: var(--v2-palette-grey-lightest);
box-shadow: none;
}
.link {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(18em / 12);
- letter-spacing: calc(0.2em / 12);
+ font-size: var(--v2-font-size-1);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+ color: var(--v2-palette-link-text);
text-transform: uppercase;
}
-.story {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(18em / 12);
- letter-spacing: calc(0.2em / 12);
+.viewContext {
+ padding-bottom: var(--v2-spacing-1);
+}
+
+.storyLabel {
+ color: var(--v2-palette-grey-main);
+ font-size: var(--v2-font-size-1);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+ margin-bottom: var(--v2-spacing-1);
text-transform: uppercase;
- color: var(--palette-grey-main);
}
.storyTitle {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: calc(18em / 12);
- letter-spacing: calc(0.2em / 12);
- color: var(--palette-text-primary);
-}
-
-.moderatedBy {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
- line-height: 1;
- letter-spacing: 0;
- color: var(--palette-text-primary);
- text-transform: uppercase;
-}
-
-.moderatedByUsername {
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: 1;
- letter-spacing: 0;
- color: var(--palette-text-primary);
- text-align: center;
- padding-top: 1px;
+ color: var(--v2-palette-story-title);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+ margin-bottom: var(--v2-spacing-1);
}
.borderless {
border-width: 0px;
box-shadow: none;
+ padding: var(--v2-spacing-2) 0;
}
.miniButton {
@@ -158,16 +153,24 @@
}
.deleted {
- background: var(--palette-grey-lightest);
+ background: var(--v2-palette-grey-lightest);
}
.timestamp {
- color: var(--palette-grey-lighter);
+ color: var(--v2-palette-timestamp);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-1);
+ line-height: var(--v2-line-height-reset);
}
.edited {
- color: var(--palette-grey-lighter);
- padding-left: var(--spacing-2)
+ color: var(--v2-palette-timestamp);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-1);
+ line-height: var(--v2-line-height-reset);
+ padding-left: var(--v2-spacing-2);
}
.selected {
@@ -176,5 +179,17 @@
.authorStatus {
padding-right: var(--spacing-2);
+ color: var(--v2-palette-timestamp);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-1);
+ line-height: var(--v2-line-height-reset);
+ padding-left: var(--v2-spacing-2);
}
+.deleted {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-body-short);
+}
diff --git a/src/core/client/admin/components/ModerateCard/ModerateCard.tsx b/src/core/client/admin/components/ModerateCard/ModerateCard.tsx
index 8c5a88532..65cf39017 100644
--- a/src/core/client/admin/components/ModerateCard/ModerateCard.tsx
+++ b/src/core/client/admin/components/ModerateCard/ModerateCard.tsx
@@ -18,8 +18,7 @@ import {
HorizontalGutter,
TextLink,
Timestamp,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import ApproveButton from "./ApproveButton";
import CommentAuthorContainer from "./CommentAuthorContainer";
@@ -146,10 +145,10 @@ const ModerateCard: FunctionComponent = ({
}, [selected]);
const commentBody = deleted ? (
-
+
This comment is no longer available. The commenter has deleted their
account.
-
+
) : (
body
@@ -185,10 +184,10 @@ const ModerateCard: FunctionComponent = ({
})}
>
- {!hideUsername && (
+ {!hideUsername && username && (
{username}
@@ -197,9 +196,7 @@ const ModerateCard: FunctionComponent = ({
{createdAt}
{edited && (
)}
= ({
/>
{inReplyTo && inReplyTo.username && (
-
-
- {inReplyTo.username}
-
+
+
+ {inReplyTo.username}
+
)}
-
- {commentBody}
-
+
+
+ {commentBody}
+
+
+
+
+
+
-
-
-
-
+
{showStory && (
-
- {": "}
-
{storyTitle} {" "}
-
+
+
+ :
+
+
{storyTitle}
+
+
+
)}
= ({
-
= ({
comment,
onUsernameClick,
@@ -29,23 +36,23 @@ const ModerateCardDetailsContainer: FunctionComponent = ({
hasDetails,
hasRevisions,
}) => {
- const [activeTab, setActiveTab] = useState<"DETAILS" | "HISTORY">(
+ const [activeTab, setActiveTab] = useState(
hasDetails ? "DETAILS" : "HISTORY"
);
return (
setActiveTab(id as "DETAILS" | "HISTORY")}
+ onTabClick={id => setActiveTab(id as DetailsTabs)}
>
{hasDetails && (
-
+
list
-
- Details
+
+ Info
diff --git a/src/core/client/admin/components/ModerateCard/ModeratedByContainer.css b/src/core/client/admin/components/ModerateCard/ModeratedByContainer.css
index 7decb5934..6ea3d6448 100644
--- a/src/core/client/admin/components/ModerateCard/ModeratedByContainer.css
+++ b/src/core/client/admin/components/ModerateCard/ModeratedByContainer.css
@@ -1,20 +1,21 @@
+$moderated-by: var(--v2-colors-mono-100);
+$moderated-by-username: var(--v2-colors-mono-900);
+
.moderatedBy {
- font-size: calc(12rem / var(--rem-base));
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
- line-height: 1;
- letter-spacing: 0;
- color: var(--palette-text-primary);
+ font-size: var(--v2-font-size-1);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+ color: $moderated-by;
text-transform: uppercase;
}
.moderatedByUsername {
- font-size: calc(14rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
- line-height: 1;
- letter-spacing: 0;
- color: var(--palette-text-primary);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-family: var(--v2-font-family-secondary);
+ line-height: var(--v2-line-height-reset);
+ color: $moderated-by-username;
text-align: center;
padding-top: 1px;
}
diff --git a/src/core/client/admin/components/ModerateCard/ModeratedByContainer.tsx b/src/core/client/admin/components/ModerateCard/ModeratedByContainer.tsx
index 2f0ddf7f7..c684fefb9 100644
--- a/src/core/client/admin/components/ModerateCard/ModeratedByContainer.tsx
+++ b/src/core/client/admin/components/ModerateCard/ModeratedByContainer.tsx
@@ -3,7 +3,7 @@ import React, { useCallback } from "react";
import { graphql } from "react-relay";
import { withFragmentContainer } from "coral-framework/lib/relay";
-import { BaseButton } from "coral-ui/components";
+import { BaseButton } from "coral-ui/components/v2";
import { ModeratedByContainer_comment } from "coral-admin/__generated__/ModeratedByContainer_comment.graphql";
import { ModeratedByContainer_viewer } from "coral-admin/__generated__/ModeratedByContainer_viewer.graphql";
diff --git a/src/core/client/admin/components/ModerateCard/RejectButton.css b/src/core/client/admin/components/ModerateCard/RejectButton.css
index 52ffd5586..229b50328 100644
--- a/src/core/client/admin/components/ModerateCard/RejectButton.css
+++ b/src/core/client/admin/components/ModerateCard/RejectButton.css
@@ -1,22 +1,22 @@
.root {
- border: 1px solid var(--palette-error-main);
+ border: 1px solid var(--v2-palette-button-outline-reject);
box-sizing: border-box;
- border-radius: var(--round-corners);
+ border-radius: var(--v2-round-corners);
width: 65px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
- color: var(--palette-error-main);
+ color: var(--v2-palette-button-outline-reject);
&:not(:disabled):active {
- background-color: var(--palette-error-main);
- color: var(--palette-common-white);
+ background-color: var(--v2-palette-button-outline-reject);
+ color: var(--v2-colors-pure-white);
}
}
.invert {
- background-color: var(--palette-error-main);
- color: var(--palette-common-white);
+ background-color: var(--v2-palette-button-outline-reject);
+ color: var(--v2-colors-pure-white);
}
.icon {
diff --git a/src/core/client/admin/components/ModerateCard/RejectButton.tsx b/src/core/client/admin/components/ModerateCard/RejectButton.tsx
index 1a3ad1191..20b030036 100644
--- a/src/core/client/admin/components/ModerateCard/RejectButton.tsx
+++ b/src/core/client/admin/components/ModerateCard/RejectButton.tsx
@@ -3,7 +3,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { BaseButton, Icon } from "coral-ui/components";
+import { BaseButton, Icon } from "coral-ui/components/v2";
import styles from "./RejectButton.css";
diff --git a/src/core/client/admin/components/ModerateCard/ToxicityLabel.css b/src/core/client/admin/components/ModerateCard/ToxicityLabel.css
index 382b14abc..be0753e1b 100644
--- a/src/core/client/admin/components/ModerateCard/ToxicityLabel.css
+++ b/src/core/client/admin/components/ModerateCard/ToxicityLabel.css
@@ -1,3 +1,11 @@
.root {
- font-size: calc(14rem / var(--rem-base));
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-body-short);
+ color: var(--v2-palette-accordion-label);
+}
+
+.likely {
+ color: var(--v2-palette-counter-badge-background-alert);
}
diff --git a/src/core/client/admin/components/ModerateCard/ToxicityLabel.tsx b/src/core/client/admin/components/ModerateCard/ToxicityLabel.tsx
index 3638447e2..a5cd1d5dd 100644
--- a/src/core/client/admin/components/ModerateCard/ToxicityLabel.tsx
+++ b/src/core/client/admin/components/ModerateCard/ToxicityLabel.tsx
@@ -1,12 +1,13 @@
+import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Counter, Typography } from "coral-ui/components";
+import { Counter } from "coral-ui/components/v2";
import styles from "./ToxicityLabel.css";
const ToxicityCounter: FunctionComponent<{ score: number }> = ({ score }) => (
- {Math.round(score * 100)}%
+ {Math.round(score * 100)}%
);
const ToxicityLabel: FunctionComponent<{
@@ -18,26 +19,20 @@ const ToxicityLabel: FunctionComponent<{
if (score > threshold) {
return (
-
- Likely
-
+ Likely
);
} else if (score <= 0.5) {
return (
- Unlikely
+ Unlikely
);
}
return (
- Maybe
+ Maybe
);
};
diff --git a/src/core/client/admin/components/ModerateCard/Username.css b/src/core/client/admin/components/ModerateCard/Username.css
index c3bd53ac0..8a586caf1 100644
--- a/src/core/client/admin/components/ModerateCard/Username.css
+++ b/src/core/client/admin/components/ModerateCard/Username.css
@@ -1,4 +1,7 @@
.root {
- line-height: 1;
- color: var(--palette-grey-dark);
+ font-size: var(--v2-font-size-3);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-family: var(--v2-font-family-secondary);
+ line-height: var(--v2-line-height-reset);
+ color: var(--v2-palette-username-emphasis);
}
diff --git a/src/core/client/admin/components/ModerateCard/Username.tsx b/src/core/client/admin/components/ModerateCard/Username.tsx
index 7a9f336cb..2318b37d4 100644
--- a/src/core/client/admin/components/ModerateCard/Username.tsx
+++ b/src/core/client/admin/components/ModerateCard/Username.tsx
@@ -1,8 +1,6 @@
import cn from "classnames";
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import styles from "./Username.css";
export interface UsernameProps {
@@ -12,13 +10,7 @@ export interface UsernameProps {
const Username: FunctionComponent = props => {
return (
-
- {props.children}
-
+ {props.children}
);
};
diff --git a/src/core/client/admin/components/ModerateCard/__snapshots__/CommentContent.spec.tsx.snap b/src/core/client/admin/components/ModerateCard/__snapshots__/CommentContent.spec.tsx.snap
index 7e0e456d7..3a2a72948 100644
--- a/src/core/client/admin/components/ModerateCard/__snapshots__/CommentContent.spec.tsx.snap
+++ b/src/core/client/admin/components/ModerateCard/__snapshots__/CommentContent.spec.tsx.snap
@@ -1,9 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
-Bob, you bad guy ",
@@ -13,9 +12,8 @@ exports[`renders correctly 1`] = `
`;
exports[`renders empty words correctly 1`] = `
-Bob, you bad guy",
diff --git a/src/core/client/admin/components/ModerateCard/__snapshots__/InReplyTo.spec.tsx.snap b/src/core/client/admin/components/ModerateCard/__snapshots__/InReplyTo.spec.tsx.snap
index 95f23149b..76107f4ef 100644
--- a/src/core/client/admin/components/ModerateCard/__snapshots__/InReplyTo.spec.tsx.snap
+++ b/src/core/client/admin/components/ModerateCard/__snapshots__/InReplyTo.spec.tsx.snap
@@ -14,13 +14,12 @@ exports[`renders correctly 1`] = `
Username={ }
id="moderate-comment-inReplyTo"
>
-
- Reply to <Username></Username>
-
+ Reply to
+
+
`;
diff --git a/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap b/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap
index 7d600f664..40019d894 100644
--- a/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap
+++ b/src/core/client/admin/components/ModerateCard/__snapshots__/MarkersContainer.spec.tsx.snap
@@ -53,16 +53,16 @@ exports[`renders all markers 1`] = `
id="moderate-marker-preMod"
>
- Pre-mod
+ Pre-Mod
Link
@@ -71,35 +71,35 @@ exports[`renders all markers 1`] = `
id="moderate-marker-bannedWord"
>
- Banned word
+ Banned Word
- Suspect word
+ Suspect Word
- Spam detected
+ Spam Detected
Toxic
@@ -108,7 +108,7 @@ exports[`renders all markers 1`] = `
id="moderate-marker-repeatPost"
>
Repeat comment
@@ -117,13 +117,13 @@ exports[`renders all markers 1`] = `
id="moderate-marker-recentHistory"
>
- Recent history
+ Recent History
- Pre-mod
+ Pre-Mod
- Banned word
+ Banned Word
Toxic
@@ -235,13 +235,13 @@ exports[`renders some markers 1`] = `
id="moderate-marker-recentHistory"
>
- Recent history
+ Recent History
@@ -41,38 +41,49 @@ exports[`renders approved correctly 1`] = `
/>
-
- content
-
+
+ content
+
+
+
+
+
+
-
@@ -161,38 +169,49 @@ exports[`renders correctly 1`] = `
/>
-
- content
-
+
+ content
+
+
+
+
+
+
-
@@ -281,38 +297,49 @@ exports[`renders dangling correctly 1`] = `
/>
-
- content
-
+
+ content
+
+
+
+
+
+
-
@@ -401,38 +425,49 @@ exports[`renders rejected correctly 1`] = `
/>
-
- content
-
+
+ content
+
+
+
+
+
+
-
@@ -520,49 +552,59 @@ exports[`renders reply correctly 1`] = `
onClick={[Function]}
/>
-
-
+
-
- Julian
-
-
+ Julian
+
-
- content
-
+
+ content
+
+
+
+
+
+
-
@@ -651,66 +690,82 @@ exports[`renders story info 1`] = `
/>
-
- content
-
+
+ content
+
+
+
+
+
+
-
+
-
-
-
-
+
+ :
-
- :
-
+
Cancer cured!
-
-
-
-
@@ -800,44 +852,57 @@ exports[`renders tombstoned when comment is deleted 1`] = `
/>
-
-
-
- This comment is no longer available. The commenter has deleted their account.
-
-
-
+
+
+ This comment is no longer available. The commenter has deleted their account.
+
+
+
+
+
+
+
+
-
Marvin
diff --git a/src/core/client/admin/components/NotAvailable.css b/src/core/client/admin/components/NotAvailable.css
index 4eef434ca..2537c2a91 100644
--- a/src/core/client/admin/components/NotAvailable.css
+++ b/src/core/client/admin/components/NotAvailable.css
@@ -1,3 +1,3 @@
.root {
- color: var(--palette-grey-light);
+ color: var(--v2-palette-table-body-disabled);
}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/CreateModeratorNoteMutation.ts b/src/core/client/admin/components/UserHistoryDrawer/CreateModeratorNoteMutation.ts
index 3523193d1..6eea9f2ef 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/CreateModeratorNoteMutation.ts
+++ b/src/core/client/admin/components/UserHistoryDrawer/CreateModeratorNoteMutation.ts
@@ -2,7 +2,6 @@ import { pick } from "lodash";
import { graphql } from "react-relay";
import { Environment } from "relay-runtime";
-import { CreateModeratorNoteMutation as MutationTypes } from "coral-admin/__generated__/CreateModeratorNoteMutation.graphql";
import { getViewer } from "coral-framework/helpers";
import { CoralContext } from "coral-framework/lib/bootstrap";
import {
@@ -13,6 +12,8 @@ import {
} from "coral-framework/lib/relay";
import { GQLUser } from "coral-framework/schema";
+import { CreateModeratorNoteMutation as MutationTypes } from "coral-admin/__generated__/CreateModeratorNoteMutation.graphql";
+
let clientMutationId = 0;
const CreateModeratorNoteMutation = createMutation(
diff --git a/src/core/client/admin/components/UserHistoryDrawer/DeleteModeratorNoteMutation.ts b/src/core/client/admin/components/UserHistoryDrawer/DeleteModeratorNoteMutation.ts
index 389f638be..dc741c630 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/DeleteModeratorNoteMutation.ts
+++ b/src/core/client/admin/components/UserHistoryDrawer/DeleteModeratorNoteMutation.ts
@@ -2,7 +2,6 @@ import { pick } from "lodash";
import { graphql } from "react-relay";
import { Environment } from "relay-runtime";
-import { DeleteModeratorNoteMutation as MutationTypes } from "coral-admin/__generated__/DeleteModeratorNoteMutation.graphql";
import { CoralContext } from "coral-framework/lib/bootstrap";
import {
commitMutationPromiseNormalized,
@@ -12,6 +11,8 @@ import {
} from "coral-framework/lib/relay";
import { GQLUser } from "coral-framework/schema";
+import { DeleteModeratorNoteMutation as MutationTypes } from "coral-admin/__generated__/DeleteModeratorNoteMutation.graphql";
+
let clientMutationId = 0;
const DeleteModeratorNoteMutation = createMutation(
diff --git a/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.css b/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.css
index bb157a307..006c84d68 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.css
@@ -1,37 +1,57 @@
+$moderator-note-bg: var(--v2-colors-grey-100);
+$moderator-note-body: var(--v2-colors-mono-500);
+$moderator-note-dot: var(--v2-colors-mono-100);
+$moderator-note-username: var(--v2-colors-mono-900);
+
.root {
-
}
.body {
- background-color: #f2f2f2;
+ font-family: var(--v2-font-family-primary);
+ font-size: var(--v2-font-size-3);
+ font-weight: var(--v2-font-weight-primary-regular);
+ line-height: var(--v2-line-height-body-short);
+ background-color: $moderator-note-bg;
border-radius: 4px;
- padding: var(--spacing-4);
+ padding: var(--v2-spacing-3);
+ color: $moderator-note-body;
+ margin-bottom: var(--v2-spacing-2);
}
.bodyType {
- color: var(--palette-text-dark);
}
.leftBy {
- padding-left: var(--spacing-4);
- padding-right: var(--spacing-1);
+ font-family: var(--v2-font-family-primary);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-regular);
+ line-height: var(--v2-line-height-reset);
+ padding-left: var(--v2-spacing-4);
+ padding-right: var(--v2-spacing-1);
position: relative;
- color: var(--palette-grey-main);
+ color: $moderator-note-body;
}
.leftBy:before {
content: "";
width: 4px;
height: 4px;
- background-color: var(--palette-grey-main);
+ background-color: ;
position: absolute;
border-radius: 50%;
- left: var(--spacing-1);
+ left: var(--v2-spacing-1);
+ background-color: $moderator-note-dot;
top: 50%;
}
.username {
- font-family: var(--font-family-serif);
- font-weight: var(--font-weight-medium);
- color: var(--palette-grey-main);
-}
\ No newline at end of file
+ font-family: var(--v2-font-family-secondary);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ line-height: var(--v2-line-height-reset);
+ font-size: var(--v2-font-size-3);
+ color: $moderator-note-username;
+}
+
+.footerLeft {
+ padding-left: var(--v2-spacing-3);
+}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.tsx b/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.tsx
index 790ae9646..1652176db 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/ModeratorNote.tsx
@@ -1,7 +1,7 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useCallback } from "react";
-import { Button, Flex, Icon, Timestamp, Typography } from "coral-ui/components";
+import { Button, Flex, Icon, Timestamp } from "coral-ui/components/v2";
import styles from "./ModeratorNote.css";
@@ -27,30 +27,27 @@ const ModeratorNote: FunctionComponent = ({
}, [id]);
return (
-
-
- {body}
-
-
+
{body}
-
+
{createdAt}
{moderator && (
- <>
+
-
- Left by:
-
+ Left by
-
- {moderator}
-
- >
+ {moderator}
+
)}
{onDelete && (
-
+
delete
Delete
diff --git a/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.css b/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.css
index a46437fed..481cc7e2b 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.css
@@ -1,29 +1,53 @@
+$recent-history-title: var(--v2-colors-mono-500);
+$recent-history-subtitle: var(--v2-colors-mono-100);
+$recent-history-info: var(--v2-colors-mono-500);
+$recent-history-triggered: var(--v2-palette-error-main);
+
.title {
text-transform: uppercase;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-3);
+ margin: 0;
+ line-height: var(--v2-line-height-body-short);
+ color: $recent-history-title;
}
.subTitle {
- color: var(--palette-grey-main);
- font-size: calc(14rem / var(--rem-base));
+ color: $recent-history-subtitle;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ margin: 0;
+ line-height: var(--v2-line-height-body-short);
}
.info {
- display: inline-block;
}
.amount {
- font-size: calc(24rem / var(--rem-base));
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-6);
+ line-height: var(--v2-line-height-reset);
+ line-height: var(--v2-line-height-reset);
+ color: $recent-history-info;
+ margin: 0;
}
.amountLabel {
- font-size: calc(14rem / var(--rem-base));
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ color: $recent-history-info;
+ margin: 0;
}
.triggered {
- color: var(--palette-error-main);
+ color: $recent-history-triggered;
}
.tooltip {
- color: var(--palette-text-primary);
+ color: $recent-history-info;
padding: 3px;
}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.tsx b/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.tsx
index 0ff568db7..9f72a35b9 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/RecentHistory.tsx
@@ -4,12 +4,11 @@ import React, { FunctionComponent } from "react";
import { reduceSeconds, UNIT } from "coral-common/helpers/i18n";
import {
- Box,
Flex,
+ HorizontalGutter,
Tooltip,
TooltipButton,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import styles from "./RecentHistory.css";
@@ -29,42 +28,39 @@ const RecentHistory: FunctionComponent = ({
const { scaled, unit } = reduceSeconds(timeFrame, [UNIT.DAYS]);
return (
-
-
-
- Recent comment history
-
-
-
-
- Calculated over the last {scaled} {unit}
-
-
-
-
-
+
+
+ Recent comment history
+
+
+
+ Calculated over the last {scaled} {unit}
+
+
+
+
+
+
{Math.round(rejectionRate * 100)}%
-
-
+
+
-
Rejected
-
+
-
-
-
- {submitted}
-
+
+
+
{submitted}
-
- Submitted
-
+ Submitted
-
-
-
+
+
+
);
};
diff --git a/src/core/client/admin/components/UserHistoryDrawer/Tabs.css b/src/core/client/admin/components/UserHistoryDrawer/Tabs.css
index 5bb53279f..378dcd443 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/Tabs.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/Tabs.css
@@ -1,3 +1,5 @@
+$indicator-dot: var(--v2-colors-blue-400);
+
.root {
height: 100%;
@@ -15,24 +17,13 @@
}
.tab {
- color: var(--palette-grey-dark);
- height: 100%;
- display: inline-flex;
- align-items: center;
- text-transform: uppercase;
- text-decoration: none;
- box-sizing: border-box;
- border-bottom: 3px solid transparent;
-
- font-size: calc(14rem / var(--rem-base));
}
.activeTab {
- color: var(--palette-primary-main);
}
.tabIcon {
- margin-right: var(--spacing-2);
+ margin-right: var(--v2-spacing-1);
}
.tabContent {
@@ -41,7 +32,7 @@
}
.container {
- height: calc(100% - var(--spacing-2) - var(--spacing-3));
+ height: calc(100% - var(--v2-spacing-2) - var(--v2-spacing-3));
display: flex;
flex-direction: column;
@@ -50,8 +41,8 @@
overflow: hidden;
- margin-bottom: var(--spacing-2);
- margin-top: var(--spacing-3);
+ margin-bottom: var(--v2-spacing-2);
+ margin-top: var(--v2-spacing-3);
}
.scrollable {
@@ -60,9 +51,9 @@
}
.redDot {
- background-color: var(--palette-error-main);
+ background-color: $indicator-dot;
width: 6px;
height: 6px;
border-radius: 50%;
margin-left: 2px;
-}
\ No newline at end of file
+}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/Tabs.tsx b/src/core/client/admin/components/UserHistoryDrawer/Tabs.tsx
index 3e0ef6729..5f626316e 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/Tabs.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/Tabs.tsx
@@ -9,7 +9,7 @@ import {
TabBar,
TabContent,
TabPane,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import UserDrawerAccountHistoryQuery from "./UserDrawerAccountHistoryQuery";
import UserDrawerNotesQuery from "./UserDrawerNotesQuery";
@@ -48,7 +48,8 @@ const UserHistoryTabs: FunctionComponent = ({ userID, notesCount }) => {
className={styles.tabBar}
>
- = ({ userID, notesCount }) => {
-
+
-
- cancel
+ close
-
+
- = ({ userID, notesCount }) => {
{notesCount > 0 &&
}
-
+
-
history
@@ -104,7 +108,7 @@ const UserHistoryTabs: FunctionComponent = ({ userID, notesCount }) => {
Account History
-
+
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserBadgesContainer.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserBadgesContainer.tsx
index 36cc5793a..bdf419266 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserBadgesContainer.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserBadgesContainer.tsx
@@ -3,7 +3,7 @@ import { graphql } from "react-relay";
import withFragmentContainer from "coral-framework/lib/relay/withFragmentContainer";
import CLASSES from "coral-stream/classes";
-import { Tag } from "coral-ui/components";
+import { Tag } from "coral-ui/components/v2";
import { UserBadgesContainer_user as UserData } from "coral-admin/__generated__/UserBadgesContainer_user.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistory.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistory.tsx
index b81882995..b5b9dd495 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistory.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistory.tsx
@@ -12,7 +12,7 @@ import {
TableCell,
TableHead,
TableRow,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import { UserDrawerAccountHistory_user } from "coral-admin/__generated__/UserDrawerAccountHistory_user.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.css b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.css
index d488ff572..cbe167f43 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.css
@@ -4,7 +4,7 @@
.callout {
width: 100%;
- font-family: var(--font-family-sans-serif);
+ font-family: var(--v2-font-family-primary);
align-content: center;
text-align: center;
-}
\ No newline at end of file
+}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.tsx
index 0a0c127fd..6bbd55361 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerAccountHistoryQuery.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
-import { CallOut, Spinner } from "coral-ui/components";
+import { CallOut, Spinner } from "coral-ui/components/v2";
import { UserDrawerAccountHistoryQuery as QueryTypes } from "coral-admin/__generated__/UserDrawerAccountHistoryQuery.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.css b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.css
index 9b02bb6fe..1014dba9e 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.css
@@ -1,23 +1,9 @@
.root {
-
}
.textArea {
width: 100%;
- box-sizing: border-box;
- height: calc(12 * var(--mini-unit));
- border-width: 1px;
- border-color: var(--palette-grey-main);
- padding: calc(0.5 * var(--mini-unit));
- border-radius: 2px;
- margin-bottom: var(--spacing-2);
- padding: var(--spacing-3);
- font-weight: var(--font-weight-regular);
- font-family: var(--font-family-sans-serif);
- font-size: calc(16rem / var(--rem-base));
- line-height: 1;
- letter-spacing: calc(0.2em / 16);
- color: var(--palette-text-primary);
+ margin-bottom: var(--v2-spacing-2);
}
.textArea:focus {
@@ -25,7 +11,6 @@
}
.form {
- padding: var(--spacing-2) 0;
- border-bottom: 1px solid rgba(0, 0, 0, 0.12);
- margin-bottom: var(--spacing-4);
+ padding: var(--v2-spacing-2) 0;
+ margin-bottom: var(--v2-spacing-4);
}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.tsx
index 6575efc92..8ff659f86 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesContainer.tsx
@@ -1,17 +1,25 @@
+import { FormApi } from "final-form";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, useCallback } from "react";
+import { Field, Form } from "react-final-form";
-import { UserDrawerNotesContainer_user as UserData } from "coral-admin/__generated__/UserDrawerNotesContainer_user.graphql";
-import { UserDrawerNotesContainer_viewer as ViewerData } from "coral-admin/__generated__/UserDrawerNotesContainer_viewer.graphql";
import {
graphql,
useMutation,
withFragmentContainer,
} from "coral-framework/lib/relay";
import { required } from "coral-framework/lib/validation";
-import { Button, Flex, HorizontalGutter } from "coral-ui/components";
-import { FormApi } from "final-form";
-import { Field, Form } from "react-final-form";
+import {
+ Button,
+ Divider,
+ Flex,
+ HorizontalGutter,
+ Textarea,
+} from "coral-ui/components/v2";
+
+import { UserDrawerNotesContainer_user as UserData } from "coral-admin/__generated__/UserDrawerNotesContainer_user.graphql";
+import { UserDrawerNotesContainer_viewer as ViewerData } from "coral-admin/__generated__/UserDrawerNotesContainer_viewer.graphql";
+
import CreateModeratorNoteMutation from "./CreateModeratorNoteMutation";
import DeleteModeratorNoteMutation from "./DeleteModeratorNoteMutation";
import ModeratorNote from "./ModeratorNote";
@@ -58,18 +66,19 @@ const UserDrawerNotesContainer: FunctionComponent = ({
data-testid="userdrawer-notes-form"
>
-
+
+ {({ input }) => (
+
+ )}
+
-
+
Add note
@@ -77,7 +86,8 @@ const UserDrawerNotesContainer: FunctionComponent = ({
)}
-
+
+
{user.moderatorNotes &&
user.moderatorNotes
.concat()
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesQuery.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesQuery.tsx
index a0c2b5c1d..6b105d3a4 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesQuery.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserDrawerNotesQuery.tsx
@@ -1,11 +1,11 @@
-import { graphql, QueryRenderer } from "coral-framework/lib/relay";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
-import { UserDrawerNotesQuery as QueryTypes } from "coral-admin/__generated__/UserDrawerNotesQuery.graphql";
+import { graphql, QueryRenderer } from "coral-framework/lib/relay";
+import { CallOut, Spinner } from "coral-ui/components/v2";
-import { CallOut, Spinner } from "coral-ui/components";
+import { UserDrawerNotesQuery as QueryTypes } from "coral-admin/__generated__/UserDrawerNotesQuery.graphql";
import UserDrawerNotesContainer from "./UserDrawerNotesContainer";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.css b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.css
index cde216310..c47715169 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.css
@@ -1,3 +1,5 @@
+$user-drawer-background: var(--v2-colors-pure-white);
+
.root {
position: fixed;
top: 0;
@@ -10,5 +12,5 @@
flex-flow: column nowrap;
flex-direction: column;
- background-color: var(--palette-common-white);
+ background-color: $user-drawer-background;
}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.tsx
index c8806915a..26adf4170 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawer.tsx
@@ -1,6 +1,7 @@
import React, { FunctionComponent } from "react";
-import { Card, Modal } from "coral-ui/components";
+import { Modal } from "coral-ui/components";
+import { Card } from "coral-ui/components/v2";
import UserHistoryDrawerQuery from "./UserHistoryDrawerQuery";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllComments.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllComments.tsx
index e91f78d12..1940cfdb2 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllComments.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllComments.tsx
@@ -7,7 +7,7 @@ import {
useLoadMore,
withPaginationContainer,
} from "coral-framework/lib/relay";
-import { Button, CallOut, Typography } from "coral-ui/components";
+import { Button, CallOut, Divider } from "coral-ui/components/v2";
import { UserHistoryDrawerAllComments_settings } from "coral-admin/__generated__/UserHistoryDrawerAllComments_settings.graphql";
import { UserHistoryDrawerAllComments_user } from "coral-admin/__generated__/UserHistoryDrawerAllComments_user.graphql";
@@ -46,12 +46,10 @@ const UserHistoryDrawerAllComments: FunctionComponent = ({
return (
);
@@ -71,7 +69,7 @@ const UserHistoryDrawerAllComments: FunctionComponent = ({
mini
/>
{// Don't show horizontal rule after last comment
- index !== comments.length - 1 && }
+ index !== comments.length - 1 && }
))}
{hasMore && (
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllCommentsQuery.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllCommentsQuery.tsx
index 868fa28d1..f16c1427d 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllCommentsQuery.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerAllCommentsQuery.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
-import { CallOut, Spinner } from "coral-ui/components";
+import { CallOut, Spinner } from "coral-ui/components/v2";
import { UserHistoryDrawerAllCommentsQuery as QueryTypes } from "coral-admin/__generated__/UserHistoryDrawerAllCommentsQuery.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.css b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.css
index dd634a4c2..168e712e4 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.css
@@ -1,6 +1,11 @@
+$user-drawer-background: var(--v2-colors-pure-white);
+$user-drawer-account-info: var(--v2-colors-mono-500);
+$user-drawer-divider: var(--v2-colors-grey-300);
+$user-drawer-status-label: var(--v2-colors-mono-500);
+
.comments {
flex: auto;
- overflow: scroll;
+ overflow: auto;
}
.close {
@@ -11,87 +16,55 @@
padding: 0px;
- background-color: var(--palette-common-white);
+ background-color: $user-drawer-background;
- border-width: 2px;
+ border-width: 1px;
border-right-width: 0px;
border-style: solid;
- border-color: var(--palette-grey-main);
+ border-color: rgba(0, 0, 0, 0.25);
border-radius: 4px 0px 0px 4px;
}
.username {
- font-family: var(--font-family-serif);
- font-size: calc(24rem / var(--rem-base));
- font-weight: 500;
- font-family: var(--font-family-serif);
- line-height: calc(36em / 24);
- letter-spacing: calc(0.2em / 24);
- margin-bottom: var(--spacing-1);
+ font-family: var(--v2-font-family-secondary);
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-size: var(--v2-font-size-6);
+ line-height: var(--v2-line-height-reset);
}
.userDetail {
- margin-bottom: var(--spacing-1);
}
.userDetailValue {
- margin-right: var(--spacing-2);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
+ color: $user-drawer-account-info;
}
.icon {
- margin-right: var(--spacing-2);
+ padding-top: 2px;
}
.copy {
- border: 1px solid var(--palette-primary-main);
- background-color: transparent;
- color: var(--palette-primary-main);
- padding-top: 2px;
- padding-bottom: 2px;
-
- &:active {
- background-color: var(--palette-primary-lightest);
- border-color: var(--palette-primary-main);
- color: var(--palette-primary-main);
- }
-}
-
-hr {
- border: 0;
- border-bottom: 1px solid var(--palette-divider);
- padding-top: 1px;
- width: 100%;
}
.divider {
- border-bottom: 1px solid var(--palette-grey-lighter);
+ border-bottom: 1px solid $user-drawer-divider;
}
.userStatus {
- margin-top: var(--spacing-1);
- margin-bottom: var(--spacing-1);
}
.userStatusLabel {
- display: inline-block;
-
- margin-right: var(--spacing-1);
-
- font-family: var(--font-family-sans-serif);
- font-style: normal;
- font-weight: 600;
- font-size: 16px;
- line-height: 14px;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-reset);
+ color: $user-drawer-status-label;
+ margin-right: var(--v2-spacing-1);
}
.userStatusChange {
- display: inline-block;
- border-style: solid;
- border-color: var(--palette-grey-lighter);
- border-width: 1px;
- border-radius: var(--round-corners);
- padding-left: var(--spacing-2);
- padding-right: var(--spacing-2);
-
- min-height: 21px;
}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.tsx
index a07a85f6e..c6ba1dcf2 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerContainer.tsx
@@ -5,7 +5,13 @@ import { UserStatusChangeContainer } from "coral-admin/components/UserStatus";
import { CopyButton } from "coral-framework/components";
import { useCoralContext } from "coral-framework/lib/bootstrap";
import { graphql, withFragmentContainer } from "coral-framework/lib/relay";
-import { Button, Flex, Icon, Typography } from "coral-ui/components";
+import {
+ Button,
+ Divider,
+ Flex,
+ HorizontalGutter,
+ Icon,
+} from "coral-ui/components/v2";
import { UserHistoryDrawerContainer_settings } from "coral-admin/__generated__/UserHistoryDrawerContainer_settings.graphql";
import { UserHistoryDrawerContainer_user } from "coral-admin/__generated__/UserHistoryDrawerContainer_user.graphql";
@@ -37,96 +43,83 @@ const UserHistoryDrawerContainer: FunctionComponent = ({
return (
<>
-
+
close
-
-
- {user.username}
-
-
-
-
-
-
-
-
-
+
+
+
+
+ {user.username}
+
+
+
+
+
+
+
Status:
-
-
-
-
-
-
-
-
-
-
-
-
-
- mail_outline
-
-
-
- {user.email}
-
-
-
-
-
-
- date_range
-
-
-
- {formatter.format(new Date(user.createdAt))}
-
-
-
-
-
- people_outline
-
-
-
- {user.id}
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+ mail_outline
+
+
+ {user.email}
+
+
+
+
+
+ date_range
+
+
+
+ {formatter.format(new Date(user.createdAt))}
+
+
+
+
+
+ people_outline
+
+
+ {user.id}
+
+
+
+
-
-
+
+
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerQuery.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerQuery.tsx
index cf971bc87..bfca2abf3 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerQuery.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerQuery.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
-import { CallOut, Spinner } from "coral-ui/components";
+import { CallOut, Spinner } from "coral-ui/components/v2";
import { UserHistoryDrawerQuery as QueryTypes } from "coral-admin/__generated__/UserHistoryDrawerQuery.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedComments.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedComments.tsx
index 236820682..a32899c92 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedComments.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedComments.tsx
@@ -7,7 +7,7 @@ import {
useLoadMore,
withPaginationContainer,
} from "coral-framework/lib/relay";
-import { Button, CallOut, Typography } from "coral-ui/components";
+import { Button, CallOut, Divider } from "coral-ui/components/v2";
import { UserHistoryDrawerRejectedComments_settings } from "coral-admin/__generated__/UserHistoryDrawerRejectedComments_settings.graphql";
import { UserHistoryDrawerRejectedComments_user } from "coral-admin/__generated__/UserHistoryDrawerRejectedComments_user.graphql";
@@ -51,9 +51,7 @@ const UserHistoryDrawerRejectedComments: FunctionComponent = ({
id="moderate-user-drawer-rejected-no-comments"
$username={user.username}
>
-
- {user.username} does not have any rejected comments.
-
+ {user.username} does not have any rejected comments.
);
@@ -73,7 +71,7 @@ const UserHistoryDrawerRejectedComments: FunctionComponent = ({
mini
/>
{// Don't show horizontal rule after last comment
- index !== comments.length - 1 && }
+ index !== comments.length - 1 && }
))}
{hasMore && (
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedCommentsQuery.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedCommentsQuery.tsx
index 9c73b98d5..7682fce23 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedCommentsQuery.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserHistoryDrawerRejectedCommentsQuery.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { ReadyState } from "react-relay";
import { graphql, QueryRenderer } from "coral-framework/lib/relay";
-import { CallOut, Spinner } from "coral-ui/components";
+import { CallOut, Spinner } from "coral-ui/components/v2";
import { UserHistoryDrawerRejectedCommentsQuery as QueryTypes } from "coral-admin/__generated__/UserHistoryDrawerRejectedCommentsQuery.graphql";
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.css b/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.css
index e69de29bb..dfa88f4e3 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.css
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.css
@@ -0,0 +1,14 @@
+$user-status-details: var(--v2-colors-mono-500);
+
+.root {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ color: $user-status-details;
+ line-height: var(--v2-line-height-body-short);
+ margin: 0 0 var(--v2-spacing-1) 0;
+}
+
+.root strong {
+ font-weight: var(--v2-font-weight-primary-bold);
+}
diff --git a/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.tsx b/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.tsx
index fe96a2317..a665b64ec 100644
--- a/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.tsx
+++ b/src/core/client/admin/components/UserHistoryDrawer/UserStatusDetailsContainer.tsx
@@ -9,11 +9,12 @@ import {
ClickOutside,
Icon,
Popover,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import { UserStatusDetailsContainer_user as UserData } from "coral-admin/__generated__/UserStatusDetailsContainer_user.graphql";
+import styles from "./UserStatusDetailsContainer.css";
+
interface Props {
user: UserData;
}
@@ -56,10 +57,10 @@ const UserStatusDetailsContainer: FunctionComponent = ({ user }) => {
$timestamp={formatter.format(new Date(activeBan.createdAt))}
strong={ }
>
-
+
Banned on {" "}
{formatter.format(new Date(activeBan.createdAt))}
-
+
{activeBan.createdBy && (
= ({ user }) => {
strong={ }
$username={activeBan.createdBy.username}
>
-
+
by
{activeBan.createdBy.username}
-
+
)}
@@ -83,10 +84,10 @@ const UserStatusDetailsContainer: FunctionComponent = ({ user }) => {
strong={ }
$username={activeSuspension.createdBy.username}
>
-
+
Suspended by
{activeSuspension.createdBy.username}
-
+
)}
= ({ user }) => {
new Date(activeSuspension.from.start)
)}
>
-
+
Start:
{formatter.format(new Date(activeSuspension.from.start))}
-
+
}
@@ -108,10 +109,10 @@ const UserStatusDetailsContainer: FunctionComponent = ({ user }) => {
)}
id="userDetails-suspension-finish"
>
-
+
End:
{formatter.format(new Date(activeSuspension.from.finish))}
-
+
)}
diff --git a/src/core/client/admin/components/UserRole/UserRoleChange.tsx b/src/core/client/admin/components/UserRole/UserRoleChange.tsx
index 0268203ac..ac982c772 100644
--- a/src/core/client/admin/components/UserRole/UserRoleChange.tsx
+++ b/src/core/client/admin/components/UserRole/UserRoleChange.tsx
@@ -10,7 +10,7 @@ import {
Dropdown,
DropdownButton,
Popover,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import UserRoleText from "./UserRoleText";
@@ -60,8 +60,10 @@ const UserRoleChange: FunctionComponent = props => (
aria-label="Change role"
className={styles.button}
onClick={toggleVisibility}
+ uppercase={false}
+ color="mono"
ref={ref}
- variant="regular"
+ variant="plain"
size="small"
>
{props.role}
diff --git a/src/core/client/admin/components/UserRole/UserRoleText.css b/src/core/client/admin/components/UserRole/UserRoleText.css
index 6d592cea1..f98400fd5 100644
--- a/src/core/client/admin/components/UserRole/UserRoleText.css
+++ b/src/core/client/admin/components/UserRole/UserRoleText.css
@@ -1,9 +1,10 @@
.root {
- font-weight: var(--font-weight-regular);
- color: var(--palette-grey-darkest);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ color: var(--v2-palette-table-body-text);
}
.commenter {
- font-weight: var(--font-weight-regular);
- color: var(--palette-grey-light);
+ color: var(--v2-palette-table-body-text);
+ font-weight: var(--v2-font-weight-primary-regular);
}
diff --git a/src/core/client/admin/components/UserStatus/BanModal.css b/src/core/client/admin/components/UserStatus/BanModal.css
index f01b54db8..4a4d28e0e 100644
--- a/src/core/client/admin/components/UserStatus/BanModal.css
+++ b/src/core/client/admin/components/UserStatus/BanModal.css
@@ -1,10 +1,13 @@
-.card {
- max-width: 500px;
+$ban-modal-text: var(--v2-colors-mono-500);
+
+.bodyText {
+ font-size: var(--v2-font-size-3);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ line-height: var(--v2-line-height-body-short);
+ color: $ban-modal-text;
}
.textArea {
- width: 100%;
- box-sizing: border-box;
height: calc(12 * var(--mini-unit));
- padding: calc(0.5 * var(--mini-unit));
}
diff --git a/src/core/client/admin/components/UserStatus/BanModal.tsx b/src/core/client/admin/components/UserStatus/BanModal.tsx
index b6c3cb355..faf2410c9 100644
--- a/src/core/client/admin/components/UserStatus/BanModal.tsx
+++ b/src/core/client/admin/components/UserStatus/BanModal.tsx
@@ -6,14 +6,15 @@ import NotAvailable from "coral-admin/components/NotAvailable";
import { GetMessage, withGetMessage } from "coral-framework/lib/i18n";
import {
Button,
- Card,
- CardCloseButton,
CheckBox,
Flex,
HorizontalGutter,
- Modal,
- Typography,
-} from "coral-ui/components";
+ Textarea,
+} from "coral-ui/components/v2";
+
+import ChangeStatusModal from "./ChangeStatusModal";
+import ChangeStatusModalHeader from "./ChangeStatusModalHeader";
+import ModalHeaderUsername from "./ModalHeaderUsername";
import styles from "./BanModal.css";
@@ -50,39 +51,45 @@ const BanModal: FunctionComponent = ({
);
return (
-
- {({ firstFocusableRef, lastFocusableRef }) => (
-
-
-
-
- }
- $username={username || }
- >
-
- Are you sure you want to ban{" "}
- {username || } ?
-
-
-
-
-
-
-
+
+
+ )}
+
+
)}
-
+
);
};
diff --git a/src/core/client/admin/components/UserStatus/ChangeStatusModal.css b/src/core/client/admin/components/UserStatus/ChangeStatusModal.css
new file mode 100644
index 000000000..91838626b
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ChangeStatusModal.css
@@ -0,0 +1,5 @@
+.root {
+ max-width: 500px;
+ padding: var(--v2-spacing-2) var(--v2-spacing-3) var(--v2-spacing-3)
+ var(--v2-spacing-3);
+}
diff --git a/src/core/client/admin/components/UserStatus/ChangeStatusModal.tsx b/src/core/client/admin/components/UserStatus/ChangeStatusModal.tsx
new file mode 100644
index 000000000..1f102bbf1
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ChangeStatusModal.tsx
@@ -0,0 +1,51 @@
+import React, { FunctionComponent, RefObject } from "react";
+
+import {
+ Card,
+ CardCloseButton,
+ Flex,
+ Modal,
+ ModalProps,
+} from "coral-ui/components/v2";
+
+import styles from "./ChangeStatusModal.css";
+
+type RenderPropsCallback = (
+ lastFocusableRef: RefObject
+) => React.ReactNode;
+
+function isRenderProp(
+ children: ModalProps["children"]
+): children is RenderPropsCallback {
+ return typeof children === "function";
+}
+
+interface Props extends Partial {
+ onClose: () => void;
+}
+
+const ChangeStatusModal: FunctionComponent = ({
+ children,
+ onClose,
+ ...rest
+}) => {
+ return (
+
+ {renderProps => (
+
+
+
+
+ {isRenderProp(children)
+ ? children.call(null, [renderProps])
+ : children}
+
+ )}
+
+ );
+};
+
+export default ChangeStatusModal;
diff --git a/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.css b/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.css
new file mode 100644
index 000000000..8222b9bb7
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.css
@@ -0,0 +1,10 @@
+$status-modal-text: var(--v2-colors-mono-500);
+
+.root {
+ font-size: var(--v2-font-size-5);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ line-height: var(--v2-line-height-title);
+ color: $status-modal-text;
+ margin: 0;
+}
diff --git a/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.tsx b/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.tsx
new file mode 100644
index 000000000..26eef3fe8
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ChangeStatusModalHeader.tsx
@@ -0,0 +1,15 @@
+import React, { FunctionComponent, HTMLAttributes } from "react";
+
+import styles from "./ChangeStatusModalHeader.css";
+
+const ChangeStatusModalHeader: FunctionComponent<
+ HTMLAttributes
+> = ({ children, ...rest }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default ChangeStatusModalHeader;
diff --git a/src/core/client/admin/components/UserStatus/ModalHeaderUsername.css b/src/core/client/admin/components/UserStatus/ModalHeaderUsername.css
new file mode 100644
index 000000000..c2d58ce09
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ModalHeaderUsername.css
@@ -0,0 +1,8 @@
+$status-modal-username: var(--v2-colors-mono-900);
+
+.root {
+ font-weight: var(--v2-font-weight-secondary-bold);
+ font-family: var(--v2-font-family-secondary);
+ color: $status-modal-username;
+ font-size: 1.4rem;
+}
diff --git a/src/core/client/admin/components/UserStatus/ModalHeaderUsername.tsx b/src/core/client/admin/components/UserStatus/ModalHeaderUsername.tsx
new file mode 100644
index 000000000..0e31e17df
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/ModalHeaderUsername.tsx
@@ -0,0 +1,9 @@
+import React, { FunctionComponent } from "react";
+
+import styles from "./ModalHeaderUsername.css";
+
+const ModalHeaderUsername: FunctionComponent<{}> = ({ children }) => {
+ return {children} ;
+};
+
+export default ModalHeaderUsername;
diff --git a/src/core/client/admin/components/UserStatus/PremodModal.css b/src/core/client/admin/components/UserStatus/PremodModal.css
index a85052914..9617ee7a5 100644
--- a/src/core/client/admin/components/UserStatus/PremodModal.css
+++ b/src/core/client/admin/components/UserStatus/PremodModal.css
@@ -1,3 +1,9 @@
-.card {
- max-width: 500px;
-}
\ No newline at end of file
+$premod-modal-text: var(--v2-colors-mono-500);
+
+.bodyText {
+ font-size: var(--v2-font-size-3);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ line-height: var(--v2-line-height-body-short);
+ color: $premod-modal-text;
+}
diff --git a/src/core/client/admin/components/UserStatus/PremodModal.tsx b/src/core/client/admin/components/UserStatus/PremodModal.tsx
index 0253ddcd6..7bb16c1b8 100644
--- a/src/core/client/admin/components/UserStatus/PremodModal.tsx
+++ b/src/core/client/admin/components/UserStatus/PremodModal.tsx
@@ -2,15 +2,11 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import NotAvailable from "coral-admin/components/NotAvailable";
-import {
- Button,
- Card,
- CardCloseButton,
- Flex,
- HorizontalGutter,
- Modal,
- Typography,
-} from "coral-ui/components";
+import { Button, Flex, HorizontalGutter } from "coral-ui/components/v2";
+
+import ChangeStatusModal from "./ChangeStatusModal";
+import ChangeStatusModalHeader from "./ChangeStatusModalHeader";
+import ModalHeaderUsername from "./ModalHeaderUsername";
import styles from "./PremodModal.css";
@@ -28,51 +24,53 @@ const PremodModal: FunctionComponent = ({
username,
}) => {
return (
-
- {({ firstFocusableRef, lastFocusableRef }) => (
-
-
-
-
- }
- $username={username || }
- >
-
- Are you sure you want to always premoderate{" "}
- {username || } ?
-
-
-
-
-
-
+
+ {({ lastFocusableRef }) => (
+
+ }
+ $username={username || }
+ >
+
+ Are you sure you want to always premoderate{" "}
+
+ {username || }
+
+ ?
+
+
+
+
+
-
-
-
-
+
+
+
)}
-
+
);
};
diff --git a/src/core/client/admin/components/UserStatus/SuspendForm.css b/src/core/client/admin/components/UserStatus/SuspendForm.css
new file mode 100644
index 000000000..296f41a4a
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/SuspendForm.css
@@ -0,0 +1,12 @@
+.textArea {
+ height: calc(12 * var(--mini-unit));
+}
+
+.subTitle {
+ font-size: var(--v2-font-size-4);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ line-height: var(--v2-line-height-title);
+ color: $suspend-modal-text;
+ margin: 0;
+}
diff --git a/src/core/client/admin/components/UserStatus/SuspendForm.tsx b/src/core/client/admin/components/UserStatus/SuspendForm.tsx
index 71e9e2343..a6bf533d5 100644
--- a/src/core/client/admin/components/UserStatus/SuspendForm.tsx
+++ b/src/core/client/admin/components/UserStatus/SuspendForm.tsx
@@ -1,6 +1,6 @@
import { Mutator } from "final-form";
import { Localized } from "fluent-react/compat";
-import React, { FunctionComponent, useCallback } from "react";
+import React, { FunctionComponent, RefObject, useCallback } from "react";
import { Field, Form } from "react-final-form";
import { ScaledUnit } from "coral-common/helpers/i18n";
@@ -11,7 +11,8 @@ import {
Flex,
HorizontalGutter,
RadioButton,
-} from "coral-ui/components";
+ Textarea,
+} from "coral-ui/components/v2";
import styles from "./SuspendModal.css";
@@ -21,6 +22,7 @@ interface Props {
getMessage: GetMessage;
organizationName: string;
onSubmit: (duration: ScaledUnit, message: string) => void;
+ lastFocusableRef: RefObject;
}
const DURATIONS: ScaledUnit[] = [
@@ -38,6 +40,7 @@ const SuspendForm: FunctionComponent = ({
getMessage,
onSubmit,
organizationName,
+ lastFocusableRef,
}) => {
const getMessageWithDuration = useCallback(
({ scaled, unit }: Pick): string => {
@@ -107,42 +110,48 @@ const SuspendForm: FunctionComponent = ({
>
{({ handleSubmit, form }) => (
-
-
- {DURATIONS.map(({ original, value, scaled, unit }) => (
-
- {({ input }) => (
-
- {
- form.mutators.setMessageValue(
- "emailMessage",
- getMessageWithDuration({ scaled, unit })
- );
- input.onChange(event);
- }}
+
+
+
+
+
+ {DURATIONS.map(({ original, value, scaled, unit }) => (
+
+ {({ input }) => (
+
-
- {scaled} {unit}
-
-
-
- )}
-
- ))}
-
+ {
+ form.mutators.setMessageValue(
+ "emailMessage",
+ getMessageWithDuration({ scaled, unit })
+ );
+ input.onChange(event);
+ }}
+ >
+
+ {scaled} {unit}
+
+
+
+ )}
+
+ ))}
+
+
{({ input }) => (
)}
diff --git a/src/core/client/admin/components/UserStatus/SuspendModal.css b/src/core/client/admin/components/UserStatus/SuspendModal.css
index 8f0292a1d..350b1036c 100644
--- a/src/core/client/admin/components/UserStatus/SuspendModal.css
+++ b/src/core/client/admin/components/UserStatus/SuspendModal.css
@@ -1,5 +1,20 @@
-.card {
- max-width: 500px;
+$suspend-modal-text: var(--v2-colors-mono-500);
+
+.bodyText {
+ font-size: var(--v2-font-size-3);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ line-height: var(--v2-line-height-body-short);
+ color: $suspend-modal-text;
+}
+
+.subTitle {
+ font-size: var(--v2-font-size-4);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ line-height: var(--v2-line-height-title);
+ color: $suspend-modal-text;
+ margin: 0;
}
.radioButton {
@@ -14,9 +29,9 @@
}
.header {
- margin: 0 0 var(--spacing-3) 0 !important;
+ margin: 0 0 var(--spacing-3) 0 !important;
}
.footer {
margin-top: var(--spacing-3);
-}
\ No newline at end of file
+}
diff --git a/src/core/client/admin/components/UserStatus/SuspendModal.tsx b/src/core/client/admin/components/UserStatus/SuspendModal.tsx
index c8cd7bdd0..7b1690e7d 100644
--- a/src/core/client/admin/components/UserStatus/SuspendModal.tsx
+++ b/src/core/client/admin/components/UserStatus/SuspendModal.tsx
@@ -4,15 +4,11 @@ import React, { FunctionComponent, useCallback, useState } from "react";
import NotAvailable from "coral-admin/components/NotAvailable";
import { ScaledUnit } from "coral-common/helpers/i18n";
import { GetMessage, withGetMessage } from "coral-framework/lib/i18n";
-import {
- Button,
- Card,
- CardCloseButton,
- Flex,
- HorizontalGutter,
- Modal,
- Typography,
-} from "coral-ui/components";
+import { Button, Flex, HorizontalGutter } from "coral-ui/components/v2";
+
+import ChangeStatusModal from "./ChangeStatusModal";
+import ChangeStatusModalHeader from "./ChangeStatusModalHeader";
+import ModalHeaderUsername from "./ModalHeaderUsername";
import SuspendForm from "./SuspendForm";
@@ -52,76 +48,75 @@ const SuspendModal: FunctionComponent = ({
);
return (
- <>
-
- {({ firstFocusableRef, lastFocusableRef }) => (
-
-
- {success && (
-
-
- }
- $duration={successDuration}
+
+ {({ lastFocusableRef }) => (
+ <>
+ {success && (
+
+ }
+ $duration={successDuration}
+ >
+
+ {username} has been
+ suspended for {successDuration}
+
+
+
+
+
-
-
-
-
-
-
- )}
- {!success && (
-
- }
- $username={username || }
- >
-
- Suspend {username || } ?
-
-
-
+
+
+ )}
+ {!success && (
+
+ }
+ $username={username || }
+ >
+
+ Suspend{" "}
+
+ {username || }
+
+ ?
+
+
+
-
-
-
-
- )}
-
- )}
-
- >
+
+
+ )}
+ >
+ )}
+
);
};
diff --git a/src/core/client/admin/components/UserStatus/UserStatus.css b/src/core/client/admin/components/UserStatus/UserStatus.css
new file mode 100644
index 000000000..b3c2e614d
--- /dev/null
+++ b/src/core/client/admin/components/UserStatus/UserStatus.css
@@ -0,0 +1,20 @@
+.root {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-reset);
+}
+
+.success {
+ color: var(--v2-palette-success-main);
+}
+
+.warning {
+ color: var(--v2-palette-error-main);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+}
+
+.error {
+ color: var(--v2-palette-error-darkest);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+}
diff --git a/src/core/client/admin/components/UserStatus/UserStatus.tsx b/src/core/client/admin/components/UserStatus/UserStatus.tsx
index 8bd83f077..1866c274e 100644
--- a/src/core/client/admin/components/UserStatus/UserStatus.tsx
+++ b/src/core/client/admin/components/UserStatus/UserStatus.tsx
@@ -1,8 +1,10 @@
+import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Flex, Typography } from "coral-ui/components";
-import { PropTypesOf } from "coral-ui/types";
+import { Flex } from "coral-ui/components/v2";
+
+import styles from "./UserStatus.css";
interface Props {
banned: boolean;
@@ -10,22 +12,18 @@ interface Props {
premod: boolean;
}
-const render = (
- color: PropTypesOf["color"],
- content: React.ReactNode
-) => (
-
+const render = (className: string, content: React.ReactNode) => (
+
{content}
-
+
);
const UserStatus: FunctionComponent = props => {
if (props.banned) {
return render(
- "error",
- // eslint-disable-next-line:jsx-wrap-multiline
+ styles.error,
Banned
@@ -33,8 +31,7 @@ const UserStatus: FunctionComponent = props => {
}
if (props.suspended) {
return render(
- "warning",
- // eslint-disable-next-line:jsx-wrap-multiline
+ styles.warning,
Suspended
@@ -42,16 +39,14 @@ const UserStatus: FunctionComponent = props => {
}
if (props.premod) {
return render(
- "warning",
- // eslint-disable-next-line:jsx-wrap-multiline
+ styles.warning,
Always Premoderated
);
}
return render(
- "success",
- // eslint-disable-next-line:jsx-wrap-multiline
+ styles.success,
Active
diff --git a/src/core/client/admin/components/UserStatus/UserStatusChange.css b/src/core/client/admin/components/UserStatus/UserStatusChange.css
index 528966bb2..ef1d4679c 100644
--- a/src/core/client/admin/components/UserStatus/UserStatusChange.css
+++ b/src/core/client/admin/components/UserStatus/UserStatusChange.css
@@ -1,6 +1,13 @@
+$status-change-button-border: var(--v2-colors-grey-400);
+
.button {
justify-content: space-between;
- padding: 0;
+ display: flex;
+}
+
+.bordered {
+ padding: 0 var(--v2-spacing-2);
+ border: 1px solid $status-change-button-border;
}
.fullWidth {
diff --git a/src/core/client/admin/components/UserStatus/UserStatusChange.tsx b/src/core/client/admin/components/UserStatus/UserStatusChange.tsx
index bbbecd6bd..a0d603532 100644
--- a/src/core/client/admin/components/UserStatus/UserStatusChange.tsx
+++ b/src/core/client/admin/components/UserStatus/UserStatusChange.tsx
@@ -9,7 +9,7 @@ import {
Dropdown,
DropdownButton,
Popover,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import styles from "./UserStatusChange.css";
@@ -25,6 +25,7 @@ interface Props {
premod: boolean;
children: React.ReactNode;
fullWidth?: boolean;
+ bordered?: boolean;
}
const UserStatusChange: FunctionComponent = ({
@@ -39,6 +40,7 @@ const UserStatusChange: FunctionComponent = ({
premod,
children,
fullWidth = true,
+ bordered = false,
}) => (
);
default:
@@ -129,7 +130,7 @@ const InviteForm: FunctionComponent = ({ lastRef, onFinish }) => {
-
- }
- >
-
- When enabled, there will be real-time loading and updating of
- comments as new comments and replies are published
-
-
-
-
-
-
+ }
+ >
+
+ }
+ >
+
+ When enabled, there will be real-time loading and updating of comments
+ as new comments and replies are published
+
+
+
+
+
);
export default CommentStreamLiveUpdates;
diff --git a/src/core/client/admin/routes/Configure/sections/Advanced/CustomCSSConfig.tsx b/src/core/client/admin/routes/Configure/sections/Advanced/CustomCSSConfig.tsx
index 52fed6edb..ce45949b7 100644
--- a/src/core/client/admin/routes/Configure/sections/Advanced/CustomCSSConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Advanced/CustomCSSConfig.tsx
@@ -2,67 +2,52 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import {
- formatEmpty,
- parseEmptyAsNull,
- ValidationMessage,
-} from "coral-framework/lib/form";
-import {
- FormField,
- HorizontalGutter,
- TextField,
- Typography,
-} from "coral-ui/components";
+import { formatEmpty, parseEmptyAsNull } from "coral-framework/lib/form";
+import { FormField, FormFieldDescription } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const CustomCSSConfig: FunctionComponent = ({ disabled }) => (
-
-
+
- }>
- Custom CSS
-
+
-
- }
- >
-
- URL of a CSS stylesheet that will override default Embed Stream
- styles. Can be internal or external.
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ }
+ >
+
+ }
+ >
+
+ URL of a CSS stylesheet that will override default Embed Stream
+ styles. Can be internal or external.
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
);
export default CustomCSSConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.css b/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.css
index 7d58b1830..2387d0792 100644
--- a/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.css
+++ b/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.css
@@ -2,7 +2,8 @@
width: 100%;
box-sizing: border-box;
padding: calc(0.5 * var(--mini-unit));
- resize: none;
+ min-height: 400px;
+ font-family: monospace;
}
.copyArea {
diff --git a/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.tsx b/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.tsx
index 316077851..fced5daf6 100644
--- a/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Advanced/EmbedCode.tsx
@@ -5,10 +5,15 @@ import React, { FunctionComponent, useMemo } from "react";
import { CopyButton } from "coral-framework/components";
import { GetMessage, withGetMessage } from "coral-framework/lib/i18n";
import { getLocationOrigin } from "coral-framework/utils";
-import { HorizontalGutter, Typography } from "coral-ui/components";
+import {
+ FieldSet,
+ FormFieldDescription,
+ HorizontalGutter,
+ Textarea,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import styles from "./EmbedCode.css";
@@ -79,28 +84,30 @@ const EmbedCode: FunctionComponent = ({ staticURI, getMessage }) => {
}, [staticURI]);
return (
-
-
-
-
-
-
-
- Copy and paste the code below into your CMS to embed Coral comment
- streams in each of your site’s stories.
-
+
+ }>Embed code
-
-
-
-
-
-
+ }
+ container={ }
+ >
+
+
+ Copy and paste the code below into your CMS to embed Coral comment
+ streams in each of your site’s stories.
+
+
+
+
+
+
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/Advanced/PermittedDomainsConfig.tsx b/src/core/client/admin/routes/Configure/sections/Advanced/PermittedDomainsConfig.tsx
index 69b65b9b5..985105ffb 100644
--- a/src/core/client/admin/routes/Configure/sections/Advanced/PermittedDomainsConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Advanced/PermittedDomainsConfig.tsx
@@ -2,75 +2,62 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import {
- colorFromMeta,
- formatStringList,
- parseStringList,
- ValidationMessage,
-} from "coral-framework/lib/form";
+import { formatStringList, parseStringList } from "coral-framework/lib/form";
import { validateStrictURLList } from "coral-framework/lib/validation";
-import {
- FormField,
- HorizontalGutter,
- TextField,
- Typography,
-} from "coral-ui/components";
+import { FormField, FormFieldDescription } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const PermittedDomainsConfig: FunctionComponent = ({ disabled }) => (
-
-
+
- }
- >
+
-
- }
- >
-
- The domains you would like to permit for Coral, e.g. your local,
- staging and production environments including the scheme (ex.
- http://localhost:3000, https://staging.domain.com,
- https://domain.com).
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ }
+ >
+
+ }
+ >
+
+ The domains you would like to permit for Coral, e.g. your local,
+ staging and production environments including the scheme (ex.
+ http://localhost:3000, https://staging.domain.com,
+ https://domain.com).
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
);
export default PermittedDomainsConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Advanced/StoryCreationConfig.tsx b/src/core/client/admin/routes/Configure/sections/Advanced/StoryCreationConfig.tsx
index 0c3c63e12..c796b32dd 100644
--- a/src/core/client/admin/routes/Configure/sections/Advanced/StoryCreationConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Advanced/StoryCreationConfig.tsx
@@ -2,100 +2,108 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { parseEmptyAsNull, ValidationMessage } from "coral-framework/lib/form";
+import { parseEmptyAsNull } from "coral-framework/lib/form";
import { ExternalLink } from "coral-framework/lib/i18n/components";
import { validateURL } from "coral-framework/lib/validation";
import {
FormField,
- HorizontalGutter,
- InputLabel,
- TextField,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ FormFieldHeader,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
+import HelperText from "../../HelperText";
import OnOffField from "../../OnOffField";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const StoryCreationConfig: FunctionComponent = ({ disabled }) => (
-
-
+
-
+
-
- Details
-
-
-
-
-
-
- Lazy story creation
-
-
- Details
-
-
-
-
-
-
-
- Story scraping
-
-
- Details
-
-
-
-
-
-
-
-
- Scraper proxy URL
-
-
-
- }
- >
-
- When specified, allows scraping requests to use the provided
- proxy. All requests will then be passed through the appropriote
- proxy as parsed by the npm proxy-agent package.
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
-
+ }
+ >
+
+
+ Advanced settings for how stories are created within Coral
+
+
+
+
+
+ Lazy story creation
+
+
+
+ Enable stories to be automatically created when they are published
+ from your CMS.
+
+
+
+
+
+
+
+
+ Story scraping
+
+
+
+ Enable story metadata to be automatically scraped when they are
+ published from your CMS.
+
+
+
+
+
+
+
+
+
+ Scraper proxy URL
+
+
+
+ }
+ >
+
+ When specified, allows scraping requests to use the provided proxy.
+ All requests will then be passed through the appropriote proxy as
+ parsed by the npm proxy-agent package.
+
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
);
export default StoryCreationConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/AccountFeaturesConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/AccountFeaturesConfig.tsx
index b299356ba..0f0f39e67 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/AccountFeaturesConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/AccountFeaturesConfig.tsx
@@ -2,17 +2,17 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import {
- FieldSet,
Flex,
FormField,
- HorizontalGutter,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ FormFieldHeader,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
+import HelperText from "../../HelperText";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
import styles from "./AccountFeaturesConfig.css";
@@ -22,123 +22,114 @@ interface Props {
const AccountFeaturesConfig: FunctionComponent = ({ disabled }) => (
-
-
- Commenter account mangement features
-
-
-
-
- You can enable and disable certain features for your commenters to
- use within their Profile. These features also assist towards GDPR
- compliance.
-
+
+ }>
+ Commenter account mangement features
+
- }>
-
- Allow users to:
-
-
-
-
-
-
- Change their usernames
-
-
-
-
- Usernames can be changed once every 14 days.
-
-
-
-
- Yes
-
- }
- offLabel={
-
- No
-
- }
- />
-
-
-
-
-
-
-
-
-
-
-
- Yes
-
- }
- offLabel={
-
- No
-
- }
- />
-
-
-
-
-
-
-
-
-
- Delete their account
-
-
-
-
- Removes all of their comment data, username, and email
- address from the site and the database.
-
-
-
-
- Yes
-
- }
- offLabel={
-
- No
-
- }
- />
-
-
-
-
-
+ }
+ >
+
+
+ You can enable and disable certain features for your commenters to use
+ within their Profile. These features also assist towards GDPR
+ compliance.
+
+
+
+
+ Allow users to:
+
+
+
+
+ Change their usernames
+
+
+
+ Usernames can be changed once every 14 days.
+
+
+
+
+ Yes
+
+ }
+ offLabel={
+
+ No
+
+ }
+ />
+
+
+
+
+
+
+
+
+
+ Yes
+
+ }
+ offLabel={
+
+ No
+
+ }
+ />
+
+
+
+
+
+
+ Delete their account
+
+
+
+ Removes all of their comment data, username, and email address
+ from the site and the database.
+
+
+
+
+ Yes
+
+ }
+ offLabel={
+
+ No
+
+ }
+ />
+
+
+
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfig.tsx
index a640240ec..d665f3075 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import { OnInitValuesFct } from "./AuthConfigContainer";
import AuthIntegrationsConfig from "./AuthIntegrationsConfig";
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigContainer.tsx b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigContainer.tsx
index 9bc454e3b..2c617665e 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigContainer.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigContainer.tsx
@@ -16,7 +16,7 @@ import {
import { getMessage } from "coral-framework/lib/i18n";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { GQLSettings } from "coral-framework/schema";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import { AuthConfigContainer_auth as AuthData } from "coral-admin/__generated__/AuthConfigContainer_auth.graphql";
import { AuthConfigContainer_settings as SettingsData } from "coral-admin/__generated__/AuthConfigContainer_settings.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigRoute.tsx
index 46b31c673..9f0fb5ad0 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/AuthConfigRoute.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { AuthConfigRouteContainerQueryResponse } from "coral-admin/__generated__/AuthConfigRouteContainerQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/AuthIntegrationsConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/AuthIntegrationsConfig.tsx
index a70850613..5413ac28b 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/AuthIntegrationsConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/AuthIntegrationsConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import { OnInitValuesFct } from "./AuthConfigContainer";
import FacebookConfigContainer from "./FacebookConfigContainer";
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/ClientIDField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/ClientIDField.tsx
index 7fbc5b8c2..2baba48e8 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/ClientIDField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/ClientIDField.tsx
@@ -2,11 +2,11 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
+import { parseEmptyAsNull } from "coral-framework/lib/form";
import { Validator } from "coral-framework/lib/validation";
-import { FormField, InputLabel, TextField } from "coral-ui/components";
+import { FormField, Label } from "coral-ui/components/v2";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
validate?: Validator;
@@ -21,23 +21,20 @@ const ClientSecretField: FunctionComponent = ({
}) => (
- Client ID
+ Client ID
{({ input, meta }) => (
- <>
-
-
- >
+
)}
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/ClientSecretField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/ClientSecretField.tsx
index 4171554ef..f968017ef 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/ClientSecretField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/ClientSecretField.tsx
@@ -4,7 +4,7 @@ import { Field } from "react-final-form";
import { parseEmptyAsNull, ValidationMessage } from "coral-framework/lib/form";
import { Validator } from "coral-framework/lib/validation";
-import { FormField, InputLabel, PasswordField } from "coral-ui/components";
+import { FormField, Label, PasswordField } from "coral-ui/components/v2";
interface Props {
validate?: Validator;
@@ -19,7 +19,7 @@ const ClientSecretField: FunctionComponent = ({
}) => (
- Client secret
+ Client secret
= ({
fullWidth
{...input}
/>
-
+
>
)}
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/ConfigBoxWithToggleField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/ConfigBoxWithToggleField.tsx
index d0c883712..8bf23b25e 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/ConfigBoxWithToggleField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/ConfigBoxWithToggleField.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
import { parseBool } from "coral-framework/lib/form";
-import { CheckBox, FormField } from "coral-ui/components";
+import { CheckBox, FormField } from "coral-ui/components/v2";
import ConfigBox from "../../ConfigBox";
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/ConfigDescription.tsx b/src/core/client/admin/routes/Configure/sections/Auth/ConfigDescription.tsx
deleted file mode 100644
index f3e9b7842..000000000
--- a/src/core/client/admin/routes/Configure/sections/Auth/ConfigDescription.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import React, { FunctionComponent } from "react";
-
-import { InputDescription } from "coral-ui/components";
-import { PropTypesOf } from "coral-ui/types";
-
-import styles from "./ConfigDescription.css";
-
-interface Props {
- container?: PropTypesOf["container"];
- children: React.ReactNode;
-}
-
-const ConfigDescription: FunctionComponent = ({
- children,
- container,
-}) => (
-
- {children}
-
-);
-
-export default ConfigDescription;
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/FacebookConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/FacebookConfig.tsx
index 3afd6c81b..f74c6a3a1 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/FacebookConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/FacebookConfig.tsx
@@ -6,8 +6,9 @@ import {
required,
validateWhen,
} from "coral-framework/lib/validation";
-import { HorizontalGutter, TextLink, Typography } from "coral-ui/components";
+import { FormFieldDescription, TextLink } from "coral-ui/components/v2";
+import Header from "../../Header";
import HorizontalRule from "../../HorizontalRule";
import ClientIDField from "./ClientIDField";
import ClientSecretField from "./ClientSecretField";
@@ -38,26 +39,26 @@ const FacebookConfig: FunctionComponent = ({
data-testid="configure-auth-facebook-container"
title={
- Login with Facebook
+
}
name="auth.integrations.facebook.enabled"
disabled={disabled}
>
{disabledInside => (
-
+ <>
}
+ br={ }
>
-
+
To enable the integration with Facebook Authentication, you need to
create and set up a web application. For more information visit:
{"https://developers.facebook.com/docs/facebook-login/web"}
-
+
-
= ({
name="auth.integrations.facebook.allowRegistration"
disabled={disabledInside}
/>
-
+ >
)}
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/GoogleConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/GoogleConfig.tsx
index 47be57f12..14cb1b359 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/GoogleConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/GoogleConfig.tsx
@@ -6,8 +6,9 @@ import {
required,
validateWhen,
} from "coral-framework/lib/validation";
-import { HorizontalGutter, TextLink, Typography } from "coral-ui/components";
+import { FormFieldDescription, TextLink } from "coral-ui/components/v2";
+import Header from "../../Header";
import HorizontalRule from "../../HorizontalRule";
import ClientIDField from "./ClientIDField";
import ClientSecretField from "./ClientSecretField";
@@ -36,28 +37,27 @@ const GoogleConfig: FunctionComponent = ({ disabled, callbackURL }) => (
- Login with Google
+
}
name="auth.integrations.google.enabled"
disabled={disabled}
>
{disabledInside => (
-
+ <>
}
>
-
+
To enable the integration with Google Authentication you need to
create and set up a web application. For more information visit:
{
"https://developers.google.com/identity/protocols/OAuth2WebServer#creatingcred"
}
-
+
-
= ({ disabled, callbackURL }) => (
name="auth.integrations.google.allowRegistration"
disabled={disabledInside}
/>
-
+ >
)}
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/LocalAuthConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/LocalAuthConfig.tsx
index 9bfea91a4..8d996bdf4 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/LocalAuthConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/LocalAuthConfig.tsx
@@ -1,8 +1,7 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { HorizontalGutter } from "coral-ui/components";
-
+import Header from "../../Header";
import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField";
import RegistrationField from "./RegistrationField";
import TargetFilterField from "./TargetFilterField";
@@ -15,14 +14,14 @@ const LocalAuthConfig: FunctionComponent = ({ disabled }) => (
- Login with email authentication
+ Login with email authentication
}
name="auth.integrations.local.enabled"
disabled={disabled}
>
{disabledInside => (
-
+ <>
@@ -36,7 +35,7 @@ const LocalAuthConfig: FunctionComponent = ({ disabled }) => (
name="auth.integrations.local.allowRegistration"
disabled={disabledInside}
/>
-
+ >
)}
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/OIDCConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/OIDCConfig.tsx
index ef3601de3..e0d78c820 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/OIDCConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/OIDCConfig.tsx
@@ -2,11 +2,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import {
- colorFromMeta,
- parseEmptyAsNull,
- ValidationMessage,
-} from "coral-framework/lib/form";
+import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
import {
composeValidatorsWhen,
Condition,
@@ -17,15 +13,18 @@ import {
Button,
Flex,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
+ FormFieldDescription,
+ FormFieldHeader,
+ HelperText,
+ Label,
TextField,
TextLink,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+import Header from "../../Header";
import HorizontalRule from "../../HorizontalRule";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
+import ValidationMessage from "../../ValidationMessage";
import { FormProps } from "./AuthConfigContainer";
import ClientIDField from "./ClientIDField";
import ClientSecretField from "./ClientSecretField";
@@ -59,52 +58,52 @@ const OIDCConfig: FunctionComponent = ({
data-testid="configure-auth-oidc-container"
title={
- Login with OIDC
+
}
name="auth.integrations.oidc.enabled"
disabled={disabled}
>
{disabledInside => (
-
+ <>
}>
-
+
{"To learn more: https://openid.net/connect/"}
-
+
-
-
- Provider name
-
-
-
- The provider of the OIDC integration. This will be used when the
- name of the provider needs to be displayed, e.g. “Log in with
- {" "}”
-
-
+
+
+ Provider name
+
+
+
+ The provider of the OIDC integration. This will be used when
+ the name of the provider needs to be displayed, e.g. “Log in
+ with
+ {" "}”
+
+
+
{({ input, meta }) => (
- <>
-
-
- >
+
)}
@@ -119,16 +118,18 @@ const OIDCConfig: FunctionComponent = ({
disabled={disabledInside}
/>
-
- Issuer
-
-
-
- After entering your Issuer information, click the Discover
- button to have Coral complete the remaining fields. You may also
- enter the information manually
-
-
+
+
+ Issuer
+
+
+
+ After entering your Issuer information, click the Discover
+ button to have Coral complete the remaining fields. You may
+ also enter the information manually
+
+
+
= ({
= ({
Discover
-
+
>
)}
- authorizationURL
+ authorizationURL
= ({
parse={parseEmptyAsNull}
>
{({ input, meta }) => (
- <>
-
-
- >
+
)}
- tokenURL
+ tokenURL
= ({
parse={parseEmptyAsNull}
>
{({ input, meta }) => (
- <>
-
-
- >
+
)}
- jwksURI
+ jwksURI
= ({
parse={parseEmptyAsNull}
>
{({ input, meta }) => (
- <>
-
-
- >
+
)}
@@ -254,7 +245,7 @@ const OIDCConfig: FunctionComponent = ({
name="auth.integrations.oidc.allowRegistration"
disabled={disabledInside}
/>
-
+ >
)}
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/RedirectField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/RedirectField.tsx
index 87ee80c09..548c61f64 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/RedirectField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/RedirectField.tsx
@@ -2,7 +2,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { CopyButton } from "coral-framework/components";
-import { Flex, FormField, InputLabel, TextField } from "coral-ui/components";
+import { Flex, FormField, Label, TextField } from "coral-ui/components/v2";
interface Props {
description?: React.ReactNode;
@@ -12,12 +12,12 @@ interface Props {
const RedirectField: FunctionComponent = ({ url, description }) => (
- Redirect URI
+ Redirect URI
{description}
-
+
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/RegistrationField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/RegistrationField.tsx
index 90946b3e8..3c6bcfeae 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/RegistrationField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/RegistrationField.tsx
@@ -5,9 +5,11 @@ import { Field } from "react-final-form";
import {
CheckBox,
FormField,
- InputDescription,
- InputLabel,
-} from "coral-ui/components";
+ FormFieldHeader,
+ Label,
+} from "coral-ui/components/v2";
+
+import HelperText from "../../HelperText";
interface Props {
name: string;
@@ -16,14 +18,16 @@ interface Props {
const RegistrationField: FunctionComponent = ({ name, disabled }) => (
-
- Registration
-
-
-
- Allow users to create a new account with this provider.
-
-
+
+
+ Registration
+
+
+
+ Allow users to create a new account with this provider.
+
+
+
{({ input }) => (
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/SSOConfig.tsx b/src/core/client/admin/routes/Configure/sections/Auth/SSOConfig.tsx
index 2bca839a8..476acf74a 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/SSOConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/SSOConfig.tsx
@@ -2,8 +2,8 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import Header from "../../Header";
import ConfigBoxWithToggleField from "./ConfigBoxWithToggleField";
import RegistrationField from "./RegistrationField";
import SSOKeyFieldContainer from "./SSOKeyFieldContainer";
@@ -18,14 +18,14 @@ const SSOConfig: FunctionComponent = ({ disabled, sso }) => (
- Login with SSO
+
}
name="auth.integrations.sso.enabled"
disabled={disabled}
>
{disabledInside => (
-
+ <>
= ({ disabled, sso }) => (
name="auth.integrations.sso.allowRegistration"
disabled={disabledInside}
/>
-
+ >
)}
);
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/SSOKeyField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/SSOKeyField.tsx
index 01734f717..866b3dbf6 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/SSOKeyField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/SSOKeyField.tsx
@@ -6,10 +6,11 @@ import {
Flex,
FormField,
Icon,
- InputLabel,
+ Label,
PasswordField,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+
+import HelperText from "../../HelperText";
import styles from "./SSOKeyField.css";
@@ -28,7 +29,7 @@ const SSOKeyField: FunctionComponent = ({
}) => (
- Key
+ Key
= ({
fullWidth
/>
-
+
KEY GENERATED AT: {keyGeneratedAt}
-
+
warning
-
+
When regenerating a key, tokens signed with the previous key will be
honored for 30 days.
-
+
@@ -60,7 +61,6 @@ const SSOKeyField: FunctionComponent = ({
= ({ disabled }) => (
-
-
+
-
+
-
+ }
+ >
}>
- Session Duration
+ Session Duration
= ({ disabled }) => (
>
{({ input, meta }) => (
<>
-
-
+
+
>
)}
-
+
);
export default SessionConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Auth/TargetFilterField.tsx b/src/core/client/admin/routes/Configure/sections/Auth/TargetFilterField.tsx
index 58e02d95c..a04c46546 100644
--- a/src/core/client/admin/routes/Configure/sections/Auth/TargetFilterField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Auth/TargetFilterField.tsx
@@ -3,7 +3,7 @@ import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
import { parseBool } from "coral-framework/lib/form";
-import { CheckBox, Flex, FormField, InputLabel } from "coral-ui/components";
+import { CheckBox, Flex, FormField, Label } from "coral-ui/components/v2";
interface Props {
label: React.ReactNode;
@@ -17,7 +17,7 @@ const TargetFilterField: FunctionComponent = ({
disabled,
}) => (
- {label}
+ {label}
{({ input }) => (
diff --git a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.css b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.css
index 27621d11d..b75ca5c70 100644
--- a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.css
+++ b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.css
@@ -1,3 +1,4 @@
.title {
display: flex;
+ justify-content: space-between;
}
diff --git a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.tsx b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.tsx
index 134390d70..28772b51f 100644
--- a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigContainer.tsx
@@ -2,30 +2,20 @@ import { FormApi } from "final-form";
import { Localized } from "fluent-react/compat";
import { RouteProps } from "found";
import React from "react";
-import { Field } from "react-final-form";
import { graphql } from "react-relay";
import { DeepNullable, DeepPartial } from "coral-common/types";
import { pureMerge } from "coral-common/utils";
-import { parseBool } from "coral-framework/lib/form";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { GQLSettings } from "coral-framework/schema";
-import {
- CheckBox,
- Flex,
- FormField,
- HorizontalGutter,
-} from "coral-ui/components";
import { EmailConfigContainer_email } from "coral-admin/__generated__/EmailConfigContainer_email.graphql";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
+import ConfigBoxWithToggleField from "../Auth/ConfigBoxWithToggleField";
import FromContainer from "./FromContainer";
import SMTPContainer from "./SMTPContainer";
-import styles from "./EmailConfigContainer.css";
-
interface Props {
form: FormApi;
submitting: boolean;
@@ -79,52 +69,30 @@ class EmailConfigContainer extends React.Component {
const { email, submitting } = this.props;
return (
-
-
- {({ input }) => (
- }
- >
-
-
- Email settings
-
-
-
-
-
-
- Enabled
-
-
-
-
-
- )}
-
-
- {({ input: { value } }) => (
-
-
-
-
- )}
-
-
+
+
+
+ }
+ name="email.enabled"
+ >
+ {disabledInside => (
+ <>
+
+
+ >
+ )}
+
);
}
}
diff --git a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigRoute.tsx
index 73ad3ea00..736f66060 100644
--- a/src/core/client/admin/routes/Configure/sections/Email/EmailConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Email/EmailConfigRoute.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { EmailConfigRouteQueryResponse } from "coral-admin/__generated__/EmailConfigRouteQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/Email/From.tsx b/src/core/client/admin/routes/Configure/sections/Email/From.tsx
index 29306270e..c023313fc 100644
--- a/src/core/client/admin/routes/Configure/sections/Email/From.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Email/From.tsx
@@ -2,79 +2,71 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import {
- colorFromMeta,
- parseEmptyAsNull,
- ValidationMessage,
-} from "coral-framework/lib/form";
+import { parseEmptyAsNull } from "coral-framework/lib/form";
import { validateEmail } from "coral-framework/lib/validation";
import {
- FieldSet,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
- TextField,
-} from "coral-ui/components";
+ FormFieldHeader,
+ HelperText,
+ Label,
+} from "coral-ui/components/v2";
+
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const From: FunctionComponent = ({ disabled }) => (
- }>
+ <>
-
- From name
-
-
-
- Name as it will appear on all outgoing emails
-
-
+
+
+ From name
+
+
+ Name as it will appear on all outgoing emails
+
+
{({ input, meta }) => (
- <>
-
-
- >
+
)}
-
- From email address
-
-
-
- Email address that will be used to send messages
-
-
+
+
+ From email address
+
+
+
+ Email address that will be used to send messages
+
+
+
{({ input, meta }) => (
- <>
-
-
- >
+
)}
-
+ >
);
export default From;
diff --git a/src/core/client/admin/routes/Configure/sections/Email/SMTP.tsx b/src/core/client/admin/routes/Configure/sections/Email/SMTP.tsx
index 73943ae40..70b78db29 100644
--- a/src/core/client/admin/routes/Configure/sections/Email/SMTP.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Email/SMTP.tsx
@@ -13,17 +13,16 @@ import {
required,
} from "coral-framework/lib/validation";
import {
- FieldSet,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
+ FormFieldHeader,
+ Label,
PasswordField,
- TextField,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+import HelperText from "../../HelperText";
import OnOffField from "../../OnOffField";
import Subheader from "../../Subheader";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import { FormProps } from "./EmailConfigContainer";
interface Props {
@@ -37,61 +36,59 @@ const isAuthenticating: Condition = (value, values) =>
Boolean(values.email.enabled && values.email.smtp.authentication);
const SMTP: FunctionComponent = ({ disabled }) => (
- }>
+ <>
-
- SMTP host
-
-
- (ex. smtp.sendgrid.com)
-
+
+
+ SMTP host
+
+
+ (ex. smtp.sendgrid.com)
+
+
{({ input, meta }) => (
- <>
-
-
- >
+
)}
-
- SMTP port
-
-
- (ex. 25)
-
+
+
+ SMTP port
+
+
+ (ex. 25)
+
+
{({ input, meta }) => (
- <>
-
-
- >
+
)}
- TLS
+ TLS
= ({ disabled }) => (
- SMTP authentication
+ SMTP authentication
= ({ disabled }) => (
- Username
+ Username
= ({ disabled }) => (
validate={composeValidatorsWhen(isAuthenticating, required)}
>
{({ input, meta }) => (
- <>
-
-
- >
+
)}
- Password
+ Password
= ({ disabled }) => (
>
)}
-
+ >
);
export default SMTP;
diff --git a/src/core/client/admin/routes/Configure/sections/General/ClosedStreamMessageConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/ClosedStreamMessageConfig.tsx
index 2c5673ba7..244ff523f 100644
--- a/src/core/client/admin/routes/Configure/sections/General/ClosedStreamMessageConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/ClosedStreamMessageConfig.tsx
@@ -4,10 +4,10 @@ import { Field } from "react-final-form";
import { MarkdownEditor } from "coral-framework/components/loadables";
import { parseEmptyAsNull } from "coral-framework/lib/form";
-import { HorizontalGutter, Spinner, Typography } from "coral-ui/components";
+import { FormFieldDescription, Spinner } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -15,41 +15,37 @@ interface Props {
}
const ClosedStreamMessageConfig: FunctionComponent = ({ disabled }) => (
-
-
-
- }
- >
- Closed comment stream message
-
-
-
-
- }
- >
-
- Write a message to appear after a story is closed for commenting.
-
+
+
+ Closed comment stream message
+
-
- {({ input, meta }) => (
- <>
- }>
-
-
-
- >
- )}
-
-
-
+ }
+ >
+ }
+ >
+
+ Write a message to appear after a story is closed for commenting.
+
+
+
+ {({ input, meta }) => (
+ <>
+ }>
+
+
+
+ >
+ )}
+
+
);
export default ClosedStreamMessageConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/ClosingCommentStreamsConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/ClosingCommentStreamsConfig.tsx
index 0e2fcc971..ee7e320a6 100644
--- a/src/core/client/admin/routes/Configure/sections/General/ClosingCommentStreamsConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/ClosingCommentStreamsConfig.tsx
@@ -2,23 +2,24 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { DURATION_UNIT, DurationField } from "coral-framework/components";
+import { colorFromMeta } from "coral-framework/lib/form";
import {
composeValidators,
required,
validateWholeNumberGreaterThan,
} from "coral-framework/lib/validation";
import {
+ DURATION_UNIT,
+ DurationField,
FieldSet,
FormField,
- HorizontalGutter,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -28,58 +29,59 @@ interface Props {
const ClosingCommentStreamsConfig: FunctionComponent = ({
disabled,
}) => (
- }>
-
+ }
+ container={ }
+ >
+ }
+ >
+
+ Set comment streams to close after a defined period of time after a
+ story’s publication
+
-
- }
- >
-
- Set comment streams to close after a defined period of time after a
- story’s publication
-
+ }>
+
+
+
+ }>
+
- }>
-
-
-
- }>
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+
+ {({ input, meta }) => (
+ <>
+
+
+ >
+ )}
+
+
+
);
export default ClosingCommentStreamsConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/CommentEditingConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/CommentEditingConfig.tsx
index 6778156a6..8a8b3696e 100644
--- a/src/core/client/admin/routes/Configure/sections/General/CommentEditingConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/CommentEditingConfig.tsx
@@ -2,22 +2,23 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { DURATION_UNIT, DurationField } from "coral-framework/components";
+import { colorFromMeta } from "coral-framework/lib/form";
import {
composeValidators,
required,
validateWholeNumberGreaterThanOrEqual,
} from "coral-framework/lib/validation";
import {
+ DURATION_UNIT,
+ DurationField,
FieldSet,
FormField,
- HorizontalGutter,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -25,51 +26,53 @@ interface Props {
}
const CommentEditingConfig: FunctionComponent = ({ disabled }) => (
-
-
-
- }
- >
-
- Set a limit on how long commenters have to edit their comments
- sitewide. Edited comments are marked as (Edited) on the comment stream
- and the moderation panel.
-
+
-
-
+ }>
+
+
+ {({ input, meta }) => (
+ <>
+
+
+ >
+ )}
+
+
+
);
export default CommentEditingConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.css b/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.css
index cc1160d68..e1033388f 100644
--- a/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.css
+++ b/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.css
@@ -1,3 +1,11 @@
.commentLengthTextInput {
width: 150px;
}
+
+.annotation {
+ color: var(--v2-palette-input-label);
+ font-size: var(--v2-font-size-3);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-title);
+}
diff --git a/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.tsx
index 77c72ba4b..a20d81b6f 100644
--- a/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/CommentLengthConfig.tsx
@@ -11,16 +11,15 @@ import {
import {
FieldSet,
FormField,
- HorizontalGutter,
- InputLabel,
- TextField,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ Label,
+ TextFieldAdornment,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import styles from "./CommentLengthConfig.css";
@@ -40,119 +39,117 @@ interface Props {
}
const CommentLengthConfig: FunctionComponent = ({ disabled }) => (
- }>
-
-
- }
- >
-
- Set minimum and maximum comment length requirements. Blank spaces at
- the beginning and the end of a comment will be trimmed.
-
+
-
+
+
+
+ {({ input, meta }) => (
+
+ }
+ placeholder={"No limit"}
+ textAlignCenter
+ />
+
+ )}
+
+
+
+
+
+ {({ input, meta }) => (
+
+ }
+ placeholder={"No limit"}
+ textAlignCenter
+ meta={meta}
+ {...input}
+ />
+
+ )}
+
+
+
);
export default CommentLengthConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/GeneralConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/GeneralConfig.tsx
index 30315cc29..790c833f5 100644
--- a/src/core/client/admin/routes/Configure/sections/General/GeneralConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/GeneralConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import ClosedStreamMessageConfigContainer from "./ClosedStreamMessageConfigContainer";
import ClosingCommentStreamsConfigContainer from "./ClosingCommentStreamsConfigContainer";
diff --git a/src/core/client/admin/routes/Configure/sections/General/GeneralConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/General/GeneralConfigRoute.tsx
index f6178e3e6..56b52d265 100644
--- a/src/core/client/admin/routes/Configure/sections/General/GeneralConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/GeneralConfigRoute.tsx
@@ -4,7 +4,7 @@ import { graphql } from "react-relay";
import { loadMarkdownEditor } from "coral-framework/components/loadables";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { GeneralConfigRouteQueryResponse } from "coral-admin/__generated__/GeneralConfigRouteQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/General/GuidelinesConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/GuidelinesConfig.tsx
index 9bcb512a5..5781e192d 100644
--- a/src/core/client/admin/routes/Configure/sections/General/GuidelinesConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/GuidelinesConfig.tsx
@@ -8,15 +8,15 @@ import { ExternalLink } from "coral-framework/lib/i18n/components";
import {
FieldSet,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
+ FormFieldHeader,
+ HelperText,
+ Label,
Spinner,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -24,39 +24,41 @@ interface Props {
}
const GuidelinesConfig: FunctionComponent = ({ disabled }) => (
- }>
-
- Community guidelines summary
-
-
- }>
-
-
-
+
+ }>Community guidelines summary
+
+ }
+ container={ }
+ >
+
+
+
+
-
+
+
-
+
Community guidelines summary
-
+
}
externalLink={ }
>
-
+
Write a summary of your community guidelines that will appear at the
top of each comment stream sitewide. Your summary can be formatted
using Markdown Syntax. More information on how to use Markdown can
be found here.
-
+
-
+
{({ input, meta }) => (
@@ -71,8 +73,8 @@ const GuidelinesConfig: FunctionComponent = ({ disabled }) => (
>
)}
-
-
+
+
);
export default GuidelinesConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/LocaleConfigContainer.tsx b/src/core/client/admin/routes/Configure/sections/General/LocaleConfigContainer.tsx
index 82088f998..9fbb0b7df 100644
--- a/src/core/client/admin/routes/Configure/sections/General/LocaleConfigContainer.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/LocaleConfigContainer.tsx
@@ -3,15 +3,15 @@ import React, { useMemo } from "react";
import { Field } from "react-final-form";
import { graphql } from "react-relay";
-import { LocaleField } from "coral-framework/components";
import { withFragmentContainer } from "coral-framework/lib/relay";
import { required } from "coral-framework/lib/validation";
-import { FormField, HorizontalGutter, Typography } from "coral-ui/components";
+import { FormFieldDescription, HorizontalGutter } from "coral-ui/components/v2";
import { LocaleConfigContainer_settings } from "coral-admin/__generated__/LocaleConfigContainer_settings.graphql";
+import ConfigBox from "../../ConfigBox";
+import LocaleField from "../../Fields/LocaleField";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -23,37 +23,33 @@ interface Props {
const LocaleConfigContainer: React.FunctionComponent = props => {
useMemo(() => props.onInitValues(props.settings), [props.onInitValues]);
return (
-
-
+
- }>
- Language
-
+
-
- }
- >
-
- Choose the language for your Coral community.
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
+ }
+ >
+
+
+
+ Choose the language for your Coral community.
+
+
+
+ {({ input, meta }) => (
+ <>
+
+
+ >
+ )}
+
-
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.css b/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.css
index e164cc8a7..3f040956d 100644
--- a/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.css
+++ b/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.css
@@ -5,4 +5,4 @@
.reactionButton {
cursor: not-allowed !important;
color: var(--palette-grey-main) !important;
-}
\ No newline at end of file
+}
diff --git a/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.tsx
index e40c2e507..2af8261af 100644
--- a/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/ReactionConfig.tsx
@@ -8,19 +8,18 @@ import {
FieldSet,
Flex,
FormField,
+ FormFieldDescription,
HorizontalGutter,
- InputLabel,
+ Label,
Option,
SelectField,
- TextField,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import { ReactionConfigContainer_settings as SettingsData } from "coral-admin/__generated__/ReactionConfigContainer_settings.graphql";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import styles from "./ReactionConfig.css";
@@ -30,146 +29,137 @@ interface Props {
}
const ReactionsConfig: FunctionComponent = ({ disabled, settings }) => (
- }>
-
-
-
-
- }
- >
-
- Allow your community to engage with one another and express themselves
- with one-click reactions. By default, Coral allows commenters to
- "Respect" each other's comments, but you may customize reaction text
- based on the needs of your community.
-
+
+ }>Reactions
-
-
-
- {({ input, meta }) => (
-
-
-
- Reaction label
-
-
-
-
-
-
-
-
- Preview
-
- null}
- />
-
-
- )}
-
-
-
-
- {({ input, meta }) => (
-
-
-
- Active reaction label
-
-
-
-
-
-
-
-
- Preview
-
- null}
- />
-
-
- )}
-
-
-
-
- {({ input, meta }) => (
-
-
-
- Sort label
-
-
-
-
-
-
-
-
- Preview
-
-
-
-
- {input.value} {" "}
-
-
-
-
- )}
-
-
-
-
-
+ }
+ container={ }
+ >
+ }>
+
+ Allow your community to engage with one another and express themselves
+ with one-click reactions. By default, Coral allows commenters to
+ "Respect" each other's comments, but you may customize reaction text
+ based on the needs of your community.
+
+
+
+ {({ input, meta }) => (
+
+
+
+ Reaction label
+
+
+
+
+
+
+
+ Preview
+
+ null}
+ />
+
+
+ )}
+
+
+ {({ input, meta }) => (
+
+
+
+ Active reaction label
+
+
+
+
+
+
+
+ Preview
+
+ null}
+ />
+
+
+ )}
+
+
+ {({ input, meta }) => (
+
+
+
+ Sort label
+
+
+
+
+
+
+
+ Preview
+
+
+
+
+ {input.value} {" "}
+
+
+
+
+ )}
+
+
);
export default ReactionsConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/SitewideCommentingConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/SitewideCommentingConfig.tsx
index 99399a7fb..b7407ae10 100644
--- a/src/core/client/admin/routes/Configure/sections/General/SitewideCommentingConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/SitewideCommentingConfig.tsx
@@ -5,17 +5,18 @@ import { Field } from "react-final-form";
import { MarkdownEditor } from "coral-framework/components/loadables";
import { parseEmptyAsNull } from "coral-framework/lib/form";
import {
+ FieldSet,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
+ FormFieldDescription,
+ FormFieldHeader,
+ HelperText,
+ Label,
Spinner,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
import ValidationMessage from "../../ValidationMessage";
interface Props {
@@ -23,56 +24,58 @@ interface Props {
}
const SitewideCommentingConfig: FunctionComponent = ({ disabled }) => (
-
-
-
-
+ }
+ container={ }
+ >
+
-
-
-
+
+
+
-
+
+
-
+
{({ input, meta }) => (
@@ -87,8 +90,8 @@ const SitewideCommentingConfig: FunctionComponent = ({ disabled }) => (
>
)}
-
-
+
+
);
export default SitewideCommentingConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/StaffConfig.tsx b/src/core/client/admin/routes/Configure/sections/General/StaffConfig.tsx
index c2bb77268..85e00133f 100644
--- a/src/core/client/admin/routes/Configure/sections/General/StaffConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/StaffConfig.tsx
@@ -2,22 +2,22 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
import { required } from "coral-framework/lib/validation";
import {
FieldSet,
Flex,
FormField,
+ FormFieldDescription,
HorizontalGutter,
- InputLabel,
+ Label,
Tag,
- TextField,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
+import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
+
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import styles from "./StaffConfig.css";
@@ -27,52 +27,50 @@ interface Props {
}
const StaffConfig: FunctionComponent = ({ disabled, settings }) => (
- }>
-
-
-
-
-
-
- Show a custom badge for staff members of your organization. This badge
- appears on the comment stream and in the admin interface.
-
+
+ }>Staff member badge
-
-
-
- {({ input, meta }) => (
-
-
-
- Badge text
-
-
-
-
-
-
-
-
- Preview
-
- {input.value && {input.value} }
-
-
- )}
-
-
-
-
-
+ }
+ container={ }
+ >
+
+
+ Show a custom badge for staff members of your organization. This badge
+ appears on the comment stream and in the admin interface.
+
+
+
+ {({ input, meta }) => (
+
+
+
+ Badge text
+
+
+
+
+
+
+
+ Preview
+
+ {input.value && {input.value} }
+
+
+ )}
+
+
);
export default StaffConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/General/StaffConfigContainer.tsx b/src/core/client/admin/routes/Configure/sections/General/StaffConfigContainer.tsx
index 48383d597..b6ff39eac 100644
--- a/src/core/client/admin/routes/Configure/sections/General/StaffConfigContainer.tsx
+++ b/src/core/client/admin/routes/Configure/sections/General/StaffConfigContainer.tsx
@@ -1,9 +1,10 @@
import React from "react";
import { graphql } from "react-relay";
-import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
import { withFragmentContainer } from "coral-framework/lib/relay";
+import { StaffConfigContainer_settings as SettingsData } from "coral-admin/__generated__/StaffConfigContainer_settings.graphql";
+
import StaffConfig from "./StaffConfig";
interface Props {
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/APIKeyField.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/APIKeyField.tsx
index f2be8b3be..cbb93f7e1 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/APIKeyField.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/APIKeyField.tsx
@@ -4,7 +4,7 @@ import { Field } from "react-final-form";
import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
import { Validator } from "coral-framework/lib/validation";
-import { FormField, InputLabel, PasswordField } from "coral-ui/components";
+import { FormField, Label, PasswordField } from "coral-ui/components/v2";
import ValidationMessage from "../../ValidationMessage";
@@ -24,9 +24,9 @@ const APIKeyField: FunctionComponent = ({
{({ input, meta }) => (
<>
-
+
API key
-
+
= ({
fullWidth
{...input}
/>
+
>
)}
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/AkismetConfig.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/AkismetConfig.tsx
index b274d1ee3..2f2804cdf 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/AkismetConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/AkismetConfig.tsx
@@ -2,7 +2,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { colorFromMeta, parseEmptyAsNull } from "coral-framework/lib/form";
+import { parseEmptyAsNull } from "coral-framework/lib/form";
import { ExternalLink } from "coral-framework/lib/i18n/components";
import {
Condition,
@@ -12,17 +12,17 @@ import {
import {
FieldSet,
FormField,
+ FormFieldDescription,
+ HelperText,
HorizontalGutter,
- InputLabel,
- TextField,
- Typography,
-} from "coral-ui/components";
+ Label,
+} from "coral-ui/components/v2";
-import ConfigurationSubHeader from "../../ConfigurationSubHeader";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import Subheader from "../../Subheader";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import APIKeyField from "./APIKeyField";
interface Props {
@@ -34,85 +34,81 @@ const isEnabled: Condition = (value, values) =>
const AkismetConfig: FunctionComponent = ({ disabled }) => {
return (
- }
data-testid="akismet-config"
- >
-
-
-
-
- }
- >
-
- Submitted comments are passed to the Akismet API for spam detection.
- If a comment is determined to be spam, it will prompt the user,
- indicating that the comment might be considered spam. If the user
- continues after this point with the still spam-like comment, the
- comment will be marked as containing spam, will not be published and
- are placed in the Pending Queue for review by a moderator. If
- approved by a moderator, the comment will be published.
-
+ title={
+
+ }>Spam detection filter
+ }
+ >
+ }
+ >
+
+ Submitted comments are passed to the Akismet API for spam detection.
+ If a comment is determined to be spam, it will prompt the user,
+ indicating that the comment might be considered spam. If the user
+ continues after this point with the still spam-like comment, the
+ comment will be marked as containing spam, will not be published and
+ are placed in the Pending Queue for review by a moderator. If approved
+ by a moderator, the comment will be published.
+
+
- }>
-
- Spam detection filter
-
-
-
-
-
- }
- >
-
- Note: You must add your active domain(s) in your Akismet account:
- https://akismet.com/account/
-
-
-
- }>
+
+ Spam detection filter
+
+
+
+
+ }>
+ Configuration
+
+ }
+ >
+
+ Note: You must add your active domain(s) in your Akismet account:
+ https://akismet.com/account/
+
+
+
+
+
+
+
+ Site URL
+
+
-
-
-
-
- Site URL
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ >
+ {({ input, meta }) => (
+
+ )}
+
+
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfig.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfig.tsx
index 5fd853967..39f5ebac3 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import AkismetConfigContainer from "./AkismetConfigContainer";
import PerspectiveConfigContainer from "./PerspectiveConfigContainer";
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfigRoute.tsx
index 05c57f7c7..c429ca49c 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/ModerationConfigRoute.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { ModerationConfigRouteQueryResponse } from "coral-admin/__generated__/ModerationConfigRouteQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/PerspectiveConfig.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/PerspectiveConfig.tsx
index b5fece1fa..cba01ba32 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/PerspectiveConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/PerspectiveConfig.tsx
@@ -23,19 +23,20 @@ import {
import {
FieldSet,
FormField,
+ FormFieldDescription,
+ FormFieldHeader,
+ HelperText,
HorizontalGutter,
- InputDescription,
- InputLabel,
- TextField,
- Typography,
-} from "coral-ui/components";
+ Label,
+ TextFieldAdornment,
+} from "coral-ui/components/v2";
-import ConfigurationSubHeader from "../../ConfigurationSubHeader";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
import PermissionField from "../../PermissionField";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import Subheader from "../../Subheader";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
import APIKeyField from "./APIKeyField";
import styles from "./PerspectiveConfig.css";
@@ -49,88 +50,89 @@ const isEnabled: Condition = (value, values) =>
const PerspectiveConfig: FunctionComponent = ({ disabled }) => {
return (
- }
data-testid="perspective-container"
- >
-
-
-
-
- }
- >
-
- Using the Perspective API, the Toxic Comment filter warns users when
- comments exceed the predefined toxicity threshold. Comments with a
- toxicity score above the threshold will not be published and are
- placed in the Pending Queue for review by a moderator. If approved
- by a moderator, the comment will be published.
-
+ title={
+
+ }>Toxic comment filter
+ }
+ >
+ }
+ >
+
+ Using the Perspective API, the Toxic Comment filter warns users when
+ comments exceed the predefined toxicity threshold. Comments with a
+ toxicity score above the threshold will not be published and are
+ placed in the Pending Queue for review by a moderator. If approved by
+ a moderator, the comment will be published.
+
+
- }>
-
- Toxic comment filter
-
-
-
+ }>
+
+ Toxic comment filter
+
+
+
-
+
+
-
+
Toxicity threshold
-
+
-
+
This value can be set a percentage between 0 and 100. This number
represents the likelihood that a comment is toxic, according to
Perspective API. By default the threshold is set to $default.
-
+
-
- {({ input, meta }) => (
- <>
- % }
- placeholder={TOXICITY_THRESHOLD_DEFAULT.toString()}
- textAlignCenter
- {...input}
- />
-
- >
- )}
-
-
+
+
+ {({ input, meta }) => (
+ %}
+ placeholder={TOXICITY_THRESHOLD_DEFAULT.toString()}
+ textAlignCenter
+ meta={meta}
+ {...input}
+ />
+ )}
+
+
-
+
+
-
+
Toxicity model
-
+
= ({ disabled }) => {
}
$default={TOXICITY_MODEL_DEFAULT}
>
-
+
Choose your Perspective Model. The default is $default. You can
find out more about model choices here.
-
+
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
- }>
+ }>
+
-
-
-
-
- }
- >
-
- For additional information on how to set up the Perspective Toxic
- Comment Filter please visit:
- https://github.com/conversationai/perspectiveapi/blob/master/quickstart.md
-
-
-
-
+
-
-
-
- Custom endpoint
-
-
-
-
- By default the endpoint is set to $default. You may override this
- here
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+
+
+ }>
+ Configuration
+
+ }
+ >
+
+ For additional information on how to set up the Perspective Toxic
+ Comment Filter please visit:
+ https://github.com/conversationai/perspectiveapi/blob/master/quickstart.md
+
+
+
+
+
+
+
+ Custom endpoint
+
+
+
+
+ By default the endpoint is set to $default. You may override this
+ here
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/PreModerationConfig.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/PreModerationConfig.tsx
index 39ea86a8d..786276618 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/PreModerationConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/PreModerationConfig.tsx
@@ -5,14 +5,13 @@ import { parseStringBool } from "coral-framework/lib/form";
import {
FieldSet,
FormField,
- HorizontalGutter,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
interface Props {
disabled: boolean;
@@ -28,40 +27,40 @@ const format = (v: "PRE" | "POST") => {
const PreModerationConfig: FunctionComponent = ({ disabled }) => {
return (
- }>
-
-
-
-
-
-
- When pre-moderation is turned on, comments will not be published
- unless approved by a moderator.
-
+
+ }>Pre-moderation
- }>
-
-
- Pre-moderate all comments sitewide
-
-
-
-
- }>
-
-
- Pre-moderate comments containing links sitewide
-
-
-
-
-
-
+ }
+ container={ }
+ >
+
+
+ When pre-moderation is turned on, comments will not be published
+ unless approved by a moderator.
+
+
+ }>
+
+ Pre-moderate all comments sitewide
+
+
+
+ }>
+
+
+ Pre-moderate comments containing links sitewide
+
+
+
+
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/Moderation/RecentCommentHistoryConfig.tsx b/src/core/client/admin/routes/Configure/sections/Moderation/RecentCommentHistoryConfig.tsx
index 4767baf89..cd253c089 100644
--- a/src/core/client/admin/routes/Configure/sections/Moderation/RecentCommentHistoryConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Moderation/RecentCommentHistoryConfig.tsx
@@ -2,12 +2,8 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
-import { DURATION_UNIT, DurationField } from "coral-framework/components";
-import {
- formatPercentage,
- parsePercentage,
- ValidationMessage,
-} from "coral-framework/lib/form";
+import { formatPercentage, parsePercentage } from "coral-framework/lib/form";
+import { hasError } from "coral-framework/lib/form/helpers";
import {
composeValidators,
required,
@@ -15,18 +11,21 @@ import {
validateWholeNumberGreaterThan,
} from "coral-framework/lib/validation";
import {
+ DURATION_UNIT,
+ DurationField,
FieldSet,
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
- TextField,
- Typography,
-} from "coral-ui/components";
+ FormFieldHeader,
+ Label,
+ TextFieldAdornment,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
+import HelperText from "../../HelperText";
import OnOffField from "../../OnOffField";
-import SectionContent from "../../SectionContent";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
+import ValidationMessage from "../../ValidationMessage";
import styles from "./RecentCommentHistoryConfig.css";
@@ -36,100 +35,105 @@ interface Props {
const RecentCommentHistoryConfig: FunctionComponent = ({ disabled }) => {
return (
- }>
-
-
- }>
+
-
+
+
+ {({ input, meta }) => (
+ %}
+ meta={meta}
+ textAlignCenter
+ {...input}
+ />
+ )}
+
+
+
);
};
diff --git a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfig.tsx b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfig.tsx
index b83300077..0663d4bf7 100644
--- a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import OrganizationContactEmailConfigContainer from "./OrganizationContactEmailConfigContainer";
import OrganizationNameConfigContainer from "./OrganizationNameConfigContainer";
diff --git a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfigRoute.tsx
index 18494effc..94e3b5c8d 100644
--- a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationConfigRoute.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { OrganizationConfigRouteQueryResponse } from "coral-admin/__generated__/OrganizationConfigRouteQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationContactEmailConfig.tsx b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationContactEmailConfig.tsx
index 7b28054da..f4eaef9f6 100644
--- a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationContactEmailConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationContactEmailConfig.tsx
@@ -7,68 +7,53 @@ import {
required,
validateEmail,
} from "coral-framework/lib/validation";
-import {
- FormField,
- HorizontalGutter,
- TextField,
- Typography,
-} from "coral-ui/components";
+import { FormFieldDescription } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const OrganizationNameConfig: FunctionComponent = ({ disabled }) => (
-
-
+
-
- }
- >
+
-
- }
- >
-
- This email address will be used as in emails and across the platform
- for community members to get in touch with the organization should
- they have any questions about the status of their accounts or
- moderation questions.
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ }
+ >
+ }>
+
+ This email address will be used as in emails and across the platform for
+ community members to get in touch with the organization should they have
+ any questions about the status of their accounts or moderation
+ questions.
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
);
export default OrganizationNameConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationNameConfig.tsx b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationNameConfig.tsx
index 5bbd3c4f9..3a1021273 100644
--- a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationNameConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationNameConfig.tsx
@@ -3,63 +3,48 @@ import React, { FunctionComponent } from "react";
import { Field } from "react-final-form";
import { required } from "coral-framework/lib/validation";
-import {
- FormField,
- HorizontalGutter,
- TextField,
- Typography,
-} from "coral-ui/components";
+import { FormFieldDescription } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const OrganizationNameConfig: FunctionComponent = ({ disabled }) => (
-
-
+
-
- }
- >
+
-
- }
- >
-
- Your organization name will appear on emails sent by Coral to your
- community and organization members
-
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ }
+ >
+ }>
+
+ Your organization name will appear on emails sent by Coral to your
+ community and organization members
+
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
);
export default OrganizationNameConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationURLConfig.tsx b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationURLConfig.tsx
index 45382f5c8..94b6a8494 100644
--- a/src/core/client/admin/routes/Configure/sections/Organization/OrganizationURLConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/Organization/OrganizationURLConfig.tsx
@@ -7,63 +7,48 @@ import {
required,
validateURL,
} from "coral-framework/lib/validation";
-import {
- FormField,
- HorizontalGutter,
- TextField,
- Typography,
-} from "coral-ui/components";
+import { FormFieldDescription } from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
-import ValidationMessage from "../../ValidationMessage";
+import TextFieldWithValidation from "../../TextFieldWithValidation";
interface Props {
disabled: boolean;
}
const OrganizationURLConfig: FunctionComponent = ({ disabled }) => (
-
-
+
-
- }
- >
+
-
- }
- >
- This URL will be used
-
-
- {({ input, meta }) => (
- <>
-
-
- >
- )}
-
-
-
-
+ }
+ >
+ }>
+ This URL will be used
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
);
export default OrganizationURLConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/BannedWordListConfig.tsx b/src/core/client/admin/routes/Configure/sections/WordList/BannedWordListConfig.tsx
index fc51cee71..7e060aafe 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/BannedWordListConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/WordList/BannedWordListConfig.tsx
@@ -3,14 +3,14 @@ import React, { FunctionComponent } from "react";
import {
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ FormFieldHeader,
+ HelperText,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import WordListTextArea from "./WordListTextArea";
import styles from "./BannedWordListConfig.css";
@@ -20,41 +20,40 @@ interface Props {
}
const BannedWordListConfig: FunctionComponent = ({ disabled }) => (
-
-
-
-
-
- }>
-
- Comments containing a word or phrase in the banned words list are
- automatically rejected and are not published.
-
+
+
+ }
+ >
+ }>
+
+ Comments containing a word or phrase in the banned words list are
+ automatically rejected and are not published.
+
+
-
+
+
-
- Banned word list
-
+ Banned word list
-
+
Separate banned words or phrases with a new line. Words/phrases are
not case sensitive.
-
+
-
-
-
-
-
-
+
+
+
+
);
export default BannedWordListConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/SuspectWordListConfig.tsx b/src/core/client/admin/routes/Configure/sections/WordList/SuspectWordListConfig.tsx
index e93dfd21e..0df3d0b39 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/SuspectWordListConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/WordList/SuspectWordListConfig.tsx
@@ -3,14 +3,14 @@ import React, { FunctionComponent } from "react";
import {
FormField,
- HorizontalGutter,
- InputDescription,
- InputLabel,
- Typography,
-} from "coral-ui/components";
+ FormFieldDescription,
+ FormFieldHeader,
+ HelperText,
+ Label,
+} from "coral-ui/components/v2";
+import ConfigBox from "../../ConfigBox";
import Header from "../../Header";
-import SectionContent from "../../SectionContent";
import WordListTextArea from "./WordListTextArea";
import styles from "./SuspectWordListConfig.css";
@@ -20,45 +20,41 @@ interface Props {
}
const SuspectWordListConfig: FunctionComponent = ({ disabled }) => (
-
-
- Suspect words and phrases
-
-
- }
- >
-
- Comments containing a word or phrase in the Suspect Words List are
- placed into the Reported Queue for moderator review and are published
- (if comments are not pre-moderated).
-
+
+ Suspect words and phrases
+ }
+ >
+ }>
+
+ Comments containing a word or phrase in the Suspect Words List are
+ placed into the Reported Queue for moderator review and are published
+ (if comments are not pre-moderated).
+
+
-
+
+
-
- Suspect word list
-
+ Suspect word list
-
+
Separate suspect words or phrases with a new line. Words/phrases are
not case sensitive.
-
+
-
-
-
-
-
-
+
+
+
+
);
export default SuspectWordListConfig;
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/WordListConfig.tsx b/src/core/client/admin/routes/Configure/sections/WordList/WordListConfig.tsx
index de2a5ab1a..307e8d50e 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/WordListConfig.tsx
+++ b/src/core/client/admin/routes/Configure/sections/WordList/WordListConfig.tsx
@@ -1,7 +1,7 @@
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import BannedWordListConfigContainer from "./BannedWordListConfigContainer";
import SuspectWordListConfigContainer from "./SuspectWordListConfigContainer";
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/WordListConfigRoute.tsx b/src/core/client/admin/routes/Configure/sections/WordList/WordListConfigRoute.tsx
index f774b7fd5..541bf6a04 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/WordListConfigRoute.tsx
+++ b/src/core/client/admin/routes/Configure/sections/WordList/WordListConfigRoute.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Delay, Spinner } from "coral-ui/components";
+import { Delay, Spinner } from "coral-ui/components/v2";
import { WordListConfigRouteQueryResponse } from "coral-admin/__generated__/WordListConfigRouteQuery.graphql";
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.css b/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.css
index ca9506664..4a5d60dd2 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.css
+++ b/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.css
@@ -1,6 +1,5 @@
.textArea {
width: 100%;
- box-sizing: border-box;
height: calc(23 * var(--mini-unit));
padding: calc(0.5 * var(--mini-unit));
}
diff --git a/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.tsx b/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.tsx
index 753d68307..c49af141b 100644
--- a/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.tsx
+++ b/src/core/client/admin/routes/Configure/sections/WordList/WordListTextArea.tsx
@@ -7,6 +7,7 @@ import {
parseNewLineDelimitedString,
} from "coral-framework/lib/form";
import { Validator } from "coral-framework/lib/validation";
+import { Textarea } from "coral-ui/components/v2";
import ValidationMessage from "../../ValidationMessage";
@@ -35,7 +36,7 @@ const WordListTextArea: FunctionComponent = ({
>
{({ input, meta }) => (
<>
- = ({ open, onClose }) => {
{({ firstFocusableRef }) => (
-
+
- Keyboard shortcuts
+ Keyboard shortcuts
-
+
-
- Navigation shortcuts
-
+ Navigation shortcuts
-
+
- Next comment
+ Next comment
-
+
- Previous comment
+ Previous comment
-
+
- Open search
+ Open search
-
+
- Jump to specific queue
+
+ Jump to specific queue
+
-
+
- Switch queues
+ Switch queues
-
+
- Toggle single-comment view
+
+ Toggle single-comment view
+
-
+
- Toggle shortcuts help
+
+ Toggle shortcuts help
+
-
+
-
- Moderation decisions
-
+ Moderation decisions
-
+
- Approve
+ Approve
-
+
- Reject
+ Reject
-
+
- Ban comment author
+
+ Ban comment author
+
diff --git a/src/core/client/admin/routes/Moderate/Moderate.css b/src/core/client/admin/routes/Moderate/Moderate.css
index 072624e16..827a273e2 100644
--- a/src/core/client/admin/routes/Moderate/Moderate.css
+++ b/src/core/client/admin/routes/Moderate/Moderate.css
@@ -1,3 +1,5 @@
+$moderate-background: var(--v2-colors-grey-100);
+
.background {
position: fixed;
top: 0;
@@ -5,7 +7,7 @@
z-index: -1;
width: 100%;
height: 100%;
- background-color: var(--palette-background-light);
+ background-color: $moderate-background;
}
.main {
diff --git a/src/core/client/admin/routes/Moderate/Moderate.tsx b/src/core/client/admin/routes/Moderate/Moderate.tsx
index 9ff64d236..a382fd553 100644
--- a/src/core/client/admin/routes/Moderate/Moderate.tsx
+++ b/src/core/client/admin/routes/Moderate/Moderate.tsx
@@ -9,7 +9,7 @@ import React, {
import MainLayout from "coral-admin/components/MainLayout";
import { HOTKEYS } from "coral-admin/constants";
import { PropTypesOf } from "coral-framework/types";
-import { SubBar } from "coral-ui/components/SubBar";
+import { SubBar } from "coral-ui/components/v2/SubBar";
import HotkeysModal from "./HotkeysModal";
import ModerateNavigationContainer from "./ModerateNavigation";
diff --git a/src/core/client/admin/routes/Moderate/ModerateContainer.tsx b/src/core/client/admin/routes/Moderate/ModerateContainer.tsx
index e93b19f94..d712b0e32 100644
--- a/src/core/client/admin/routes/Moderate/ModerateContainer.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateContainer.tsx
@@ -3,7 +3,7 @@ import React from "react";
import { graphql } from "react-relay";
import { withRouteConfig } from "coral-framework/lib/router";
-import { Spinner } from "coral-ui/components";
+import { Spinner } from "coral-ui/components/v2";
import { ModerateContainerQueryResponse } from "coral-admin/__generated__/ModerateContainerQuery.graphql";
diff --git a/src/core/client/admin/routes/Moderate/ModerateNavigation/Navigation.tsx b/src/core/client/admin/routes/Moderate/ModerateNavigation/Navigation.tsx
index d2dbe5e1f..375ad0958 100644
--- a/src/core/client/admin/routes/Moderate/ModerateNavigation/Navigation.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateNavigation/Navigation.tsx
@@ -5,7 +5,7 @@ import key from "keymaster";
import React, { FunctionComponent, useEffect, useMemo } from "react";
import { getModerationLink } from "coral-admin/helpers";
-import { Counter, Icon, SubBarNavigation } from "coral-ui/components";
+import { Counter, Icon, SubBarNavigation } from "coral-ui/components/v2";
import NavigationLink from "./NavigationLink";
diff --git a/src/core/client/admin/routes/Moderate/ModerateNavigation/NavigationLink.tsx b/src/core/client/admin/routes/Moderate/ModerateNavigation/NavigationLink.tsx
index 7a495d7ac..5b8933544 100644
--- a/src/core/client/admin/routes/Moderate/ModerateNavigation/NavigationLink.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateNavigation/NavigationLink.tsx
@@ -1,7 +1,7 @@
import { Link, LocationDescriptor } from "found";
import React, { FunctionComponent } from "react";
-import { SubBarNavigationItem } from "coral-ui/components";
+import { SubBarNavigationItem } from "coral-ui/components/v2";
interface Props {
children: React.ReactNode;
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.css
index fb44f494d..d192c8a7a 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.css
@@ -1,7 +1,10 @@
+@import "variables.css";
+
.root {
height: calc(6 * var(--mini-unit));
- background-color: #013f68;
+ background-color: $story-search-background;
margin-top: -1px;
+ border-bottom: 0;
}
.bumpZIndex {
@@ -18,3 +21,7 @@
padding: 0;
list-style: none;
}
+
+.groupIcon {
+ margin-right: var(--v2-spacing-2);
+}
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.tsx
index 59cdf0dcb..b40b318fa 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Bar.tsx
@@ -9,7 +9,7 @@ import React, {
} from "react";
import { Form } from "react-final-form";
-import { Backdrop, Icon, Popover, SubBar } from "coral-ui/components";
+import { Backdrop, Icon, Popover, SubBar } from "coral-ui/components/v2";
import { combineEventHandlers } from "coral-ui/helpers";
import {
useBlurOnEsc,
@@ -128,7 +128,9 @@ const Bar: FunctionComponent = ({ title, options, onSearch }) => {
- search {" "}
+
+ search
+ {" "}
Search results
@@ -144,7 +146,9 @@ const Bar: FunctionComponent = ({ title, options, onSearch }) => {
- search {" "}
+
+ search
+ {" "}
Search results (Most recent first)
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.css
index a21a43fcb..a34d4be89 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.css
@@ -1,48 +1,57 @@
+@import "variables.css";
+
.root {
width: calc(94 * var(--mini-unit));
height: calc(4 * var(--mini-unit));
}
.begin {
- background-color: var(--palette-primary-darkest);
- border-top-left-radius: var(--round-corners);
- border-bottom-left-radius: var(--round-corners);
+ background-color: $story-search-input-background;
+ border-top-left-radius: var(--v2-round-corners);
+ border-bottom-left-radius: var(--v2-round-corners);
min-width: calc(5 * var(--mini-unit));
flex-shrink: 0;
pointer-events: none;
}
.beginStories {
- font-size: calc(13rem / var(--rem-base));
- font-weight: var(--font-weight-medium);
- font-family: var(--font-family-sans-serif);
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-family: var(--v2-font-family-primary);
line-height: 1.5;
- letter-spacing: calc(0.2em / 13);
- color: var(--palette-text-light);
+ color: $story-search-input-label;
text-transform: uppercase;
padding-right: calc(0.25 * var(--mini-unit));
}
.searchIcon {
padding: 0 calc(0.5 * var(--mini-unit)) 0 calc(0.75 * var(--mini-unit));
- font-weight: var(--font-weight-medium);
- color: var(--palette-text-light);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ color: $story-search-input-label;
}
.end {
min-width: calc(5 * var(--mini-unit));
- background-color: var(--palette-primary-darkest);
- border-top-right-radius: var(--round-corners);
- border-bottom-right-radius: var(--round-corners);
+ background-color: $story-search-input-background;
+ border-top-right-radius: var(--v2-round-corners);
+ border-bottom-right-radius: var(--v2-round-corners);
flex-shrink: 0;
}
.searchButton {
- composes: button from "coral-ui/shared/typography.css";
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: 1.28;
+
+ background-color: $story-search-button-background;
+ color: $story-search-button-foreground;
+ border-left: 1px solid $story-search-button-background;
+ border-radius: var(--v2-round-corners);
+
padding: 0 calc(1 * var(--mini-unit));
- color: var(--palette-text-light);
- border-left: 1px solid var(--palette-text-light);
height: calc(4 * var(--mini-unit) - 4px);
+ margin-right: var(--spacing-1);
&:disabled {
cursor: pointer;
@@ -50,16 +59,20 @@
}
.input {
- composes: inputText placeholderPseudo from "coral-ui/shared/typography.css";
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: 1.25;
+
position: relative;
display: block;
padding: calc(0.5 * var(--mini-unit));
box-sizing: border-box;
width: 100%;
align-self: stretch;
- color: var(--palette-text-light);
+ color: $story-search-input-text;
border: 0;
- background-color: var(--palette-primary-darkest);
+ background-color: $story-search-input-background;
margin: 0;
&:focus {
@@ -67,7 +80,7 @@
}
&::placeholder {
- color: var(--palette-text-light);
+ color: $story-search-input-text;
opacity: 0.5;
}
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.tsx
index 2be24c9a9..1d8c6064b 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Field.tsx
@@ -4,7 +4,7 @@ import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, HTMLAttributes, Ref } from "react";
import { Field as FormField } from "react-final-form";
-import { BaseButton, Flex, Icon } from "coral-ui/components";
+import { BaseButton, Flex, Icon } from "coral-ui/components/v2";
import styles from "./Field.css";
@@ -59,9 +59,7 @@ const Field: FunctionComponent = ({
[styles.inputWithTitle]: !focused,
})}
placeholder={
- focused
- ? "Use quotation marks around each search term (e.g. “team”, “St. Louis”)"
- : title
+ focused ? "search by story title, author, url, id, etc." : title
}
aria-label="Search or jump to story..."
autoComplete="off"
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/GoToAriaInfo.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/GoToAriaInfo.tsx
index ca773c30d..542e86dbd 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/GoToAriaInfo.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/GoToAriaInfo.tsx
@@ -1,7 +1,7 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { AriaInfo } from "coral-ui/components";
+import { AriaInfo } from "coral-ui/components/v2";
const GoToAriaInfo: FunctionComponent = () => (
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Group.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Group.css
index 9430e49b5..89e059e15 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Group.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Group.css
@@ -1,3 +1,5 @@
+@import "variables.css";
+
.root {
margin: 0;
padding: 0;
@@ -7,18 +9,18 @@
.title {
display: flex;
align-items: center;
- height: calc(3 * var(--mini-unit));
+ height: calc(5 * var(--mini-unit));
padding-left: calc(1.5 * var(--mini-unit));
- background: var(--palette-text-primary);
+ background: $story-search-group-background;
+ color: $story-search-group-foreground;
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-medium);
- font-size: calc(13rem / var(--rem-base));
- line-height: calc(16em / 14);
- color: var(--palette-text-light);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: 1.25;
text-transform: uppercase;
}
.light {
- background: var(--palette-grey-light);
+ background: $story-search-results-heading-background;
}
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.css
index 5004483db..5a7a38a2c 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.css
@@ -1,6 +1,8 @@
+@import "variables.css";
+
.root {
&:not(:first-child) {
- border-top: 1px solid var(--palette-divider);
+ border-top: 1px solid var(--v2-palette-divider);
}
&[aria-selected="true"] {
@mixin outline;
@@ -8,12 +10,12 @@
}
.link {
- justify-content: left;
+ justify-content: center;
min-height: calc(4 * var(--mini-unit));
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-medium);
- font-size: calc(16rem / var(--rem-base));
- line-height: calc(16em / 16);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-family-primary-semi-bold);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
}
.icon {
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.tsx
index 67e9fbe7f..6285217df 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateAllOption.tsx
@@ -2,7 +2,7 @@ import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, HTMLAttributes } from "react";
-import { Button, Icon } from "coral-ui/components";
+import { Button, Icon } from "coral-ui/components/v2";
import styles from "./ModerateAllOption.css";
@@ -28,8 +28,8 @@ const ModerateAllOption: FunctionComponent = ({
>
= ({
Moderate all stories
- arrow_forward
+
+ keyboard_arrow_right
+
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateSearchBarContainer.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateSearchBarContainer.tsx
index ae0f6433c..d9b7be652 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateSearchBarContainer.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/ModerateSearchBarContainer.tsx
@@ -13,7 +13,7 @@ import { getModerationLink } from "coral-admin/helpers";
import { useEffectWhenChanged } from "coral-framework/hooks";
import { useFetch, withFragmentContainer } from "coral-framework/lib/relay";
import { PropTypesOf } from "coral-framework/types";
-import { Flex, Spinner } from "coral-ui/components";
+import { Flex, Spinner } from "coral-ui/components/v2";
import { blur } from "coral-ui/helpers";
import {
ListBoxOptionClickOrEnterHandler,
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Option.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Option.css
index a3d7f4053..fab914ef7 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/Option.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/Option.css
@@ -1,6 +1,8 @@
+@import "variables.css";
+
.root {
&:not(:first-child) {
- border-top: 1px solid var(--palette-divider);
+ border-top: 1px solid var(--v2-palette-divider);
}
&[aria-selected="true"] .container {
@mixin outline;
@@ -11,29 +13,29 @@
padding: var(--mini-unit) calc(2.5 * var(--mini-unit));
box-sizing: border-box;
&:hover {
- background: var(--palette-grey-lightest);
+ background: $story-search-story-hover;
}
}
.title {
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-medium);
- font-size: calc(16rem / var(--rem-base));
- line-height: calc(16em / 16);
- color: var(--palette-text-primary);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
+ color: $story-search-story-title;
}
.titleWithDetails {
- font-size: calc(14rem / var(--rem-base));
+ font-size: var(--v2-font-size-3);
}
.details {
padding-top: 3px;
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-regular);
- font-size: calc(14rem / var(--rem-base));
- line-height: calc(14em / 14);
- color: var(--palette-grey-dark);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-reset);
+ color: $story-search-story-detail;
}
.link {
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.css
index 33f97929e..c511d12ea 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.css
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.css
@@ -1,3 +1,5 @@
+@import "variables.css";
+
.root {
&[aria-selected="true"] {
@mixin outline;
@@ -9,19 +11,20 @@
justify-content: center;
align-items: center;
- background: var(--palette-primary-dark);
+ background: $story-search-results-see-all-background;
min-height: calc(3 * var(--mini-unit));
- font-family: var(--font-family-sans-serif);
- font-weight: var(--font-weight-medium);
- font-size: calc(13rem / var(--rem-base));
- line-height: calc(16em / 13);
- color: var(--palette-text-light);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
+ color: $story-search-results-see-all-label;
text-decoration: none;
text-transform: uppercase;
+
&:hover {
- background: var(--palette-primary-darkest);
+ background: $story-search-results-see-all-hover;
}
}
@@ -30,4 +33,6 @@
padding-left: calc(0.5 * var(--mini-unit));
line-height: calc(16em / 13);
margin-top: -2px;
+
+ color: $story-search-results-see-all-label;
}
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.tsx b/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.tsx
index a0ab83b6c..eeedfa954 100644
--- a/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.tsx
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/SeeAllOption.tsx
@@ -2,7 +2,7 @@ import cn from "classnames";
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent, HTMLAttributes } from "react";
-import { Icon } from "coral-ui/components";
+import { Icon } from "coral-ui/components/v2";
import styles from "./SeeAllOption.css";
@@ -30,7 +30,9 @@ const SeeAllOption: FunctionComponent = ({
See all results
- arrow_forward
+
+ keyboard_arrow_right
+
);
diff --git a/src/core/client/admin/routes/Moderate/ModerateSearchBar/variables.css b/src/core/client/admin/routes/Moderate/ModerateSearchBar/variables.css
new file mode 100644
index 000000000..41889c718
--- /dev/null
+++ b/src/core/client/admin/routes/Moderate/ModerateSearchBar/variables.css
@@ -0,0 +1,25 @@
+$story-search-background: var(--v2-colors-teal-600);
+
+$story-search-story-title: var(--v2-colors-mono-900);
+$story-search-story-detail: var(--v2-colors-mono-100);
+$story-search-story-background: var(--v2-colors-pure-white);
+$story-search-story-hover: var(--v2-colors-grey-100);
+
+$story-search-input-text: var(--v2-colors-mono-100);
+$story-search-input-label: var(--v2-colors-mono-500);
+$story-search-input-background: var(--v2-colors-pure-white);
+
+$story-search-button-background: var(--v2-colors-blue-500);
+$story-search-button-foreground: var(--v2-colors-pure-white);
+
+$story-search-group-background: var(--v2-colors-blue-500);
+$story-search-group-foreground: var(--v2-colors-pure-white);
+
+$story-search-results-heading: var(--v2-colors-white-500);
+$story-search-results-heading-background: var(--v2-colors-grey-500);
+
+$story-search-results-see-all-label: var(--v2-colors-white-500);
+$story-search-results-see-all-background: var(--v2-colors-blue-500);
+$story-search-results-see-all-hover: var(--v2-colors-blue-400);
+$story-search-results-see-all-border: var(--v2-colors-grey-400);
+$story-search-results-see-all-divider: var(--v2-colors-grey-300);
diff --git a/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.css b/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.css
index c551f82e9..ab1f5bda1 100644
--- a/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.css
+++ b/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.css
@@ -1,5 +1,7 @@
.root {
- composes: bodyCopy from "coral-ui/shared/typography.css";
- color: var(--palette-grey-dark);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-body-short);
text-align: center;
}
diff --git a/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.tsx b/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.tsx
index 9eef5a6f5..f981a69b1 100644
--- a/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.tsx
+++ b/src/core/client/admin/routes/Moderate/Queue/EmptyMessage.tsx
@@ -2,7 +2,7 @@ import cn from "classnames";
import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
-import { Card } from "coral-ui/components";
+import { Card } from "coral-ui/components/v2";
import styles from "./EmptyMessage.css";
diff --git a/src/core/client/admin/routes/Moderate/Queue/LoadingQueue.tsx b/src/core/client/admin/routes/Moderate/Queue/LoadingQueue.tsx
index 53f416f7b..f00392792 100644
--- a/src/core/client/admin/routes/Moderate/Queue/LoadingQueue.tsx
+++ b/src/core/client/admin/routes/Moderate/Queue/LoadingQueue.tsx
@@ -1,6 +1,6 @@
import React, { FunctionComponent } from "react";
-import { Flex, Spinner } from "coral-ui/components";
+import { Flex, Spinner } from "coral-ui/components/v2";
const LoadingQueue: FunctionComponent = () => (
diff --git a/src/core/client/admin/routes/Moderate/Queue/Queue.tsx b/src/core/client/admin/routes/Moderate/Queue/Queue.tsx
index 2098ec5be..bbcf37b7c 100644
--- a/src/core/client/admin/routes/Moderate/Queue/Queue.tsx
+++ b/src/core/client/admin/routes/Moderate/Queue/Queue.tsx
@@ -5,7 +5,7 @@ import React, { FunctionComponent, useCallback, useState } from "react";
import AutoLoadMore from "coral-admin/components/AutoLoadMore";
import ModerateCardContainer from "coral-admin/components/ModerateCard";
import UserHistoryDrawer from "coral-admin/components/UserHistoryDrawer";
-import { Button, Flex, HorizontalGutter } from "coral-ui/components";
+import { Button, Flex, HorizontalGutter } from "coral-ui/components/v2";
import { useHotkey } from "coral-ui/hooks";
import { PropTypesOf } from "coral-ui/types";
import QueueWrapper from "./QueueWrapper";
@@ -99,7 +99,6 @@ const Queue: FunctionComponent = ({
(
- Not Found
+ Not Found
);
diff --git a/src/core/client/admin/routes/Stories/EmptyMessage.css b/src/core/client/admin/routes/Stories/EmptyMessage.css
index 7b933aa00..ab1f5bda1 100644
--- a/src/core/client/admin/routes/Stories/EmptyMessage.css
+++ b/src/core/client/admin/routes/Stories/EmptyMessage.css
@@ -1,3 +1,7 @@
.root {
- font-size: calc(18rem / var(--rem-base));
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-body-short);
+ text-align: center;
}
diff --git a/src/core/client/admin/routes/Stories/EmptyMessage.tsx b/src/core/client/admin/routes/Stories/EmptyMessage.tsx
index 5f5aa8de6..c31fd9795 100644
--- a/src/core/client/admin/routes/Stories/EmptyMessage.tsx
+++ b/src/core/client/admin/routes/Stories/EmptyMessage.tsx
@@ -1,15 +1,11 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import styles from "./EmptyMessage.css";
const EmptyMessage: FunctionComponent = props => (
-
- There are currently no published stories.
-
+ There are currently no published stories.
);
diff --git a/src/core/client/admin/routes/Stories/NoMatchMessage.css b/src/core/client/admin/routes/Stories/NoMatchMessage.css
index 7b933aa00..ab1f5bda1 100644
--- a/src/core/client/admin/routes/Stories/NoMatchMessage.css
+++ b/src/core/client/admin/routes/Stories/NoMatchMessage.css
@@ -1,3 +1,7 @@
.root {
- font-size: calc(18rem / var(--rem-base));
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-body-short);
+ text-align: center;
}
diff --git a/src/core/client/admin/routes/Stories/NoMatchMessage.tsx b/src/core/client/admin/routes/Stories/NoMatchMessage.tsx
index cd8b7a073..3a09939ab 100644
--- a/src/core/client/admin/routes/Stories/NoMatchMessage.tsx
+++ b/src/core/client/admin/routes/Stories/NoMatchMessage.tsx
@@ -1,15 +1,13 @@
import { Localized } from "fluent-react/compat";
import React, { FunctionComponent } from "react";
-import { Typography } from "coral-ui/components";
-
import styles from "./NoMatchMessage.css";
const NoMatchMessage: FunctionComponent = props => (
-
+
We could not find any stories matching your criteria.
-
+
);
diff --git a/src/core/client/admin/routes/Stories/StoryRow.css b/src/core/client/admin/routes/Stories/StoryRow.css
index 7e92327d1..fdb9903b9 100644
--- a/src/core/client/admin/routes/Stories/StoryRow.css
+++ b/src/core/client/admin/routes/Stories/StoryRow.css
@@ -16,5 +16,4 @@
padding-bottom: 15px;
}
.statusColumn {
- vertical-align: top;
}
diff --git a/src/core/client/admin/routes/Stories/StoryRow.tsx b/src/core/client/admin/routes/Stories/StoryRow.tsx
index 5440de70c..b2d28696a 100644
--- a/src/core/client/admin/routes/Stories/StoryRow.tsx
+++ b/src/core/client/admin/routes/Stories/StoryRow.tsx
@@ -4,7 +4,7 @@ import React, { FunctionComponent } from "react";
import NotAvailable from "coral-admin/components/NotAvailable";
import { getModerationLink } from "coral-admin/helpers";
import { PropTypesOf } from "coral-framework/types";
-import { TableCell, TableRow, TextLink } from "coral-ui/components";
+import { TableCell, TableRow, TextLink } from "coral-ui/components/v2";
import StoryStatus from "./StoryStatus";
diff --git a/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusChange.tsx b/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusChange.tsx
index df8ad426c..eae78de7d 100644
--- a/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusChange.tsx
+++ b/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusChange.tsx
@@ -10,7 +10,7 @@ import {
Dropdown,
DropdownButton,
Popover,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import StoryStatusText from "./StoryStatusText";
@@ -62,7 +62,9 @@ const StoryStatusChange: FunctionComponent = props => (
className={styles.button}
onClick={toggleVisibility}
ref={ref}
- variant="regular"
+ color="mono"
+ uppercase={false}
+ variant="plain"
size="small"
>
{props.status}
diff --git a/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusText.css b/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusText.css
index adebfb388..264800e04 100644
--- a/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusText.css
+++ b/src/core/client/admin/routes/Stories/StoryStatus/StoryStatusText.css
@@ -1,9 +1,9 @@
.root {
- font-weight: var(--font-weight-regular);
- color: var(--palette-grey-light);
+ font-weight: var(--v2-font-weight-primary-regular);
+ color: var(--v2-palette-table-body-disabled);
}
.open {
- font-weight: var(--font-weight-regular);
- color: var(--palette-success-main);
+ font-weight: var(--v2-font-weight-primary-regular);
+ color: var(--v2-palette-success-main);
}
diff --git a/src/core/client/admin/routes/Stories/StoryTable.css b/src/core/client/admin/routes/Stories/StoryTable.css
index 064fbed8b..91d679245 100644
--- a/src/core/client/admin/routes/Stories/StoryTable.css
+++ b/src/core/client/admin/routes/Stories/StoryTable.css
@@ -11,5 +11,7 @@
width: 15%;
}
.clickToModerate {
- font-size: calc(12rem / var(--rem-base));
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ color: var(--v2-palette-table-header-alt-text);
}
diff --git a/src/core/client/admin/routes/Stories/StoryTable.tsx b/src/core/client/admin/routes/Stories/StoryTable.tsx
index 6eb8eea82..4cb6fb7f0 100644
--- a/src/core/client/admin/routes/Stories/StoryTable.tsx
+++ b/src/core/client/admin/routes/Stories/StoryTable.tsx
@@ -3,14 +3,14 @@ import React, { FunctionComponent } from "react";
import AutoLoadMore from "coral-admin/components/AutoLoadMore";
import { PropTypesOf } from "coral-framework/types";
-import { Flex, HorizontalGutter, Spinner } from "coral-ui/components";
+import { Flex, HorizontalGutter, Spinner } from "coral-ui/components/v2";
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
-} from "coral-ui/components/Table";
+} from "coral-ui/components/v2/Table";
import EmptyMessage from "./EmptyMessage";
import NoMatchMessage from "./NoMatchMessage";
diff --git a/src/core/client/admin/routes/Stories/StoryTableContainer.tsx b/src/core/client/admin/routes/Stories/StoryTableContainer.tsx
index 8a1a5f701..c0ae70580 100644
--- a/src/core/client/admin/routes/Stories/StoryTableContainer.tsx
+++ b/src/core/client/admin/routes/Stories/StoryTableContainer.tsx
@@ -8,7 +8,7 @@ import {
withPaginationContainer,
} from "coral-framework/lib/relay";
import { GQLSTORY_STATUS_RL } from "coral-framework/schema";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import { StoryTableContainer_query as QueryData } from "coral-admin/__generated__/StoryTableContainer_query.graphql";
import { StoryTableContainerPaginationQueryVariables } from "coral-admin/__generated__/StoryTableContainerPaginationQuery.graphql";
diff --git a/src/core/client/admin/routes/Stories/StoryTableFilter.css b/src/core/client/admin/routes/Stories/StoryTableFilter.css
index a187c6ee9..c5083875f 100644
--- a/src/core/client/admin/routes/Stories/StoryTableFilter.css
+++ b/src/core/client/admin/routes/Stories/StoryTableFilter.css
@@ -1,10 +1,4 @@
-.legend {
- margin-bottom: 2px;
- text-transform: uppercase;
-}
-
.textField {
- height: 31px;
width: calc(45 * var(--mini-unit));
}
diff --git a/src/core/client/admin/routes/Stories/StoryTableFilter.tsx b/src/core/client/admin/routes/Stories/StoryTableFilter.tsx
index df1c8ef1c..38a8053f7 100644
--- a/src/core/client/admin/routes/Stories/StoryTableFilter.tsx
+++ b/src/core/client/admin/routes/Stories/StoryTableFilter.tsx
@@ -7,12 +7,13 @@ import {
Button,
FieldSet,
Flex,
+ HorizontalGutter,
Icon,
+ Label,
Option,
SelectField,
TextField,
- Typography,
-} from "coral-ui/components";
+} from "coral-ui/components/v2";
import styles from "./StoryTableFilter.css";
@@ -26,91 +27,88 @@ interface Props {
const StoryTableFilter: FunctionComponent = props => (
-
-
- Search
-
-
-
- props.onSetSearchFilter(search)
- }
- >
- {({ handleSubmit }) => (
-
-
- {({ input }) => (
-
-
-
- search
-
-
- }
- />
-
- )}
-
-
- )}
-
-
-
-
-
- Show Me
-
-
-
-
- props.onSetStatusFilter((e.target.value as any) || null)
+
+
+ Search
+
+
+ props.onSetSearchFilter(search)
}
>
-
- All Stories
-
-
- Open Stories
-
-
- Closed Stories
-
-
-
+ {({ handleSubmit }) => (
+
+
+ {({ input }) => (
+
+
+
+ search
+
+
+ }
+ />
+
+ )}
+
+
+ )}
+
+
+
+
+
+
+ Show Me
+
+
+
+ props.onSetStatusFilter((e.target.value as any) || null)
+ }
+ >
+
+ All Stories
+
+
+ Open Stories
+
+
+ Closed Stories
+
+
+
+
);
diff --git a/src/core/client/admin/test/community/__snapshots__/community.spec.tsx.snap b/src/core/client/admin/test/community/__snapshots__/community.spec.tsx.snap
index 092ce58ab..3feb4f57b 100644
--- a/src/core/client/admin/test/community/__snapshots__/community.spec.tsx.snap
+++ b/src/core/client/admin/test/community/__snapshots__/community.spec.tsx.snap
@@ -9,181 +9,189 @@ exports[`renders community 1`] = `
className="Box-root HorizontalGutter-root HorizontalGutter-double"
>
-
- Search
-
-
-
+ Search
+
+
-
-
+
-
- search
-
-
+
+ search
+
+
+
-
-
+
+
-
- Show Me
-
-
-
+
+
-
- All Roles
-
-
+ All Roles
+
+
+
+ Commenters
+
+
+
+
+ Admins
+
+
+ Moderators
+
+
+ Staff
+
+
+
+
-
- Commenters
-
-
-
-
- Admins
-
-
- Moderators
-
-
- Staff
-
-
-
-
-
- expand_more
-
+ expand_more
+
+
-
-
-
-
- All Statuses
-
-
+ All Statuses
+
+
+ Active
+
+
+ Suspended
+
+
+ Banned
+
+
+ Always pre-moderate
+
+
+
- Active
-
-
- Suspended
-
-
- Banned
-
-
- Always pre-moderate
-
-
-
-
- expand_more
-
+
+ expand_more
+
+
-
+
@@ -191,8 +199,8 @@ exports[`renders community 1`] = `
data-testid="invite-users"
>
@@ -325,9 +329,9 @@ exports[`renders community 1`] = `
className="TableCell-root UserRow-usernameColumn TableCell-body"
>
@@ -427,9 +427,9 @@ exports[`renders community 1`] = `
className="TableCell-root UserRow-usernameColumn TableCell-body"
>
@@ -529,9 +525,9 @@ exports[`renders community 1`] = `
className="TableCell-root UserRow-usernameColumn TableCell-body"
>
-
- Search
-
-
-
+ Search
+
+
-
-
+
-
- search
-
-
+
+ search
+
+
+
-
-
+
+
-
- Show Me
-
-
-
+
+
-
- All Roles
-
-
+ All Roles
+
+
+
+ Commenters
+
+
+
+
+ Admins
+
+
+ Moderators
+
+
+ Staff
+
+
+
+
-
- Commenters
-
-
-
-
- Admins
-
-
- Moderators
-
-
- Staff
-
-
-
-
-
- expand_more
-
+ expand_more
+
+
-
-
-
-
- All Statuses
-
-
+ All Statuses
+
+
+ Active
+
+
+ Suspended
+
+
+ Banned
+
+
+ Always pre-moderate
+
+
+
- Active
-
-
- Suspended
-
-
- Banned
-
-
- Always pre-moderate
-
-
-
-
- expand_more
-
+
+ expand_more
+
+
-
+
@@ -855,8 +859,8 @@ exports[`renders empty community 1`] = `
data-testid="invite-users"
>
-
We could not find anyone in your community matching your criteria.
-
+
diff --git a/src/core/client/admin/test/configure/__snapshots__/advanced.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/advanced.spec.tsx.snap
index 93d3f652d..6398439bf 100644
--- a/src/core/client/admin/test/configure/__snapshots__/advanced.spec.tsx.snap
+++ b/src/core/client/admin/test/configure/__snapshots__/advanced.spec.tsx.snap
@@ -95,8 +95,8 @@ exports[`renders configure advanced 1`] = `
className="Box-root HorizontalGutter-root HorizontalGutter-double"
>
-
- Embed code
-
+
+
+
+
- Copy and paste the code below into your CMS to embed Coral comment streams in
+
+ Copy and paste the code below into your CMS to embed Coral comment streams in
each of your site’s stories.
-
-
+
+
"
- />
-
-
+
-
- Copy
-
-
-
+
+
+ Copy
+
+
+
+
-
- Custom CSS
-
-
-
+
- URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
-
+ Custom CSS
+
+
+
+
+
+
-
+
+ URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.
+
+
-
- Comment stream live updates
-
-
-
+
- When enabled, there will be real-time loading and updating of comments.
+ Comment stream live updates
+
+
+
+
+
+
+
+
+ When enabled, there will be real-time loading and updating of comments.
When disabled, users will have to refresh the page to see new comments.
-
-
-
- Permitted domains
-
-
-
+
- Domains where your Coral instance is allowed to be embedded
+ Permitted domains
+
+
+
+
+
+
+
+
+ Domains where your Coral instance is allowed to be embedded
including the scheme (ex. http://localhost:3000, https://staging.domain.com,
https://domain.com).
-
-
-
- Story creation
-
-
- Advanced settings for how stories are created within Coral.
-
+
+
+ Story creation
+
+
+
-
-
+
+
- Lazy story creation
-
-
- Enable stories to be automatically created when they are published from your CMS.
-
+
+ Lazy story creation
+
+
+ Enable stories to be automatically created when they are published from your CMS.
+
+
-
-
-
- Story scraping
-
-
- Enable story metadata to be automatically scraped when they are published from your CMS.
-
+
+ Story scraping
+
+
+ Enable story metadata to be automatically scraped when they are published from your CMS.
+
+
-
-
-
- Scraper proxy url
-
-
- When specified, allows scraping requests to use the provided
+
+ Scraper proxy url
+
+
+ When specified, allows scraping requests to use the provided
proxy. All requests will then be passed through the appropriote
proxy as parsed by the
-
- npm proxy-agent
-
- package.
-
+
+ npm proxy-agent
+
+ package.
+
+
diff --git a/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap
index 3eff5535c..52603fd56 100644
--- a/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap
+++ b/src/core/client/admin/test/configure/__snapshots__/auth.spec.tsx.snap
@@ -2,20 +2,22 @@
exports[`change settings: during submit: oidc without errors 1`] = `
-
+
Login with OpenID Connect
-
+
To learn more:
-
Redirect URI
@@ -97,8 +96,8 @@ exports[`change settings: during submit: oidc without errors 1`] = `
/>
-
- Provider name
-
-
- The provider of the OpenID Connect integration. This will be used when the name of the provider
-needs to be displayed, e.g. “Log in with <Facebook>”.
-
-
+
+ Provider name
+
+
+ The provider of the OpenID Connect integration. This will be used when the name of the provider
+needs to be displayed, e.g. “Log in with <Facebook>”.
+
+
+
Client secret
@@ -227,19 +238,23 @@ needs to be displayed, e.g. “Log in with <Facebook>”.
-
- Issuer
-
-
- After entering your Issuer information, click the Discover button to have Coral complete
+
+ Issuer
+
+
+ After entering your Issuer information, click the Discover button to have Coral complete
the remaining fields. You may also enter the information manually.
-
+
+
@@ -263,8 +278,8 @@ the remaining fields. You may also enter the information manually.
/>
Use OpenID Connect login on
@@ -432,21 +459,25 @@ the remaining fields. You may also enter the information manually.
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with Facebook
-
+
To enable the integration with Facebook Authentication,
you need to create and set up a web application.
@@ -554,14 +587,11 @@ For more information visit:
.
-
Redirect URI
@@ -581,8 +611,8 @@ For more information visit:
/>
Client secret
@@ -677,10 +711,10 @@ For more information visit:
Use Facebook login on
@@ -744,21 +778,25 @@ For more information visit:
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with OpenID Connect
-
+
To learn more:
-
Redirect URI
@@ -890,8 +927,8 @@ exports[`change settings: enable oidc configure box 1`] = `
/>
-
- Provider name
-
-
- The provider of the OpenID Connect integration. This will be used when the name of the provider
-needs to be displayed, e.g. “Log in with <Facebook>”.
-
-
+
+ Provider name
+
+
+ The provider of the OpenID Connect integration. This will be used when the name of the provider
+needs to be displayed, e.g. “Log in with <Facebook>”.
+
+
+
Client secret
@@ -1020,19 +1069,23 @@ needs to be displayed, e.g. “Log in with <Facebook>”.
-
- Issuer
-
-
- After entering your Issuer information, click the Discover button to have Coral complete
+
+ Issuer
+
+
+ After entering your Issuer information, click the Discover button to have Coral complete
the remaining fields. You may also enter the information manually.
-
+
+
@@ -1056,8 +1109,8 @@ the remaining fields. You may also enter the information manually.
/>
Use OpenID Connect login on
@@ -1225,21 +1290,25 @@ the remaining fields. You may also enter the information manually.
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with OpenID Connect
-
+
To learn more:
-
Redirect URI
@@ -1371,8 +1439,8 @@ exports[`change settings: oidc validation errors 1`] = `
/>
-
- Provider name
-
-
- The provider of the OpenID Connect integration. This will be used when the name of the provider
-needs to be displayed, e.g. “Log in with <Facebook>”.
-
-
+
+ Provider name
+
+
+ The provider of the OpenID Connect integration. This will be used when the name of the provider
+needs to be displayed, e.g. “Log in with <Facebook>”.
+
-
- warning
-
-
- This field is required.
-
+
+
+
+
+ warning
+
+
+ This field is required.
+
+
Client secret
@@ -1526,7 +1606,7 @@ needs to be displayed, e.g. “Log in with <Facebook>”.
-
- Issuer
-
-
- After entering your Issuer information, click the Discover button to have Coral complete
+
+ Issuer
+
+
+ After entering your Issuer information, click the Discover button to have Coral complete
the remaining fields. You may also enter the information manually.
-
+
+
@@ -1576,8 +1660,8 @@ the remaining fields. You may also enter the information manually.
/>
Use OpenID Connect login on
@@ -1797,21 +1893,25 @@ the remaining fields. You may also enter the information manually.
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
Key
@@ -1905,7 +2005,7 @@ exports[`regenerate sso key 1`] = `
KEY GENERATED AT:
11/12/2018, 11:26 PM
@@ -1923,15 +2023,15 @@ exports[`regenerate sso key 1`] = `
warning
When regenerating a key, tokens signed with the previous key will be honored for 30 days.
-
- Commenter account management features
-
-
+
+ Commenter account management features
+
+
+
+
+
+
- You can enable and disable certain features for your commenters to use
+
+ You can enable and disable certain features for your commenters to use
within their Profile. These features also assist towards GDPR
compliance.
-
-
-
- Allow users to:
-
+
+
+ Allow users to:
+
Change their usernames
Usernames can be changed once every 14 days.
@@ -2166,26 +2273,22 @@ compliance.
-
-
Download their comments
Commenters can download a csv of their comment history.
@@ -2244,26 +2347,22 @@ compliance.
-
-
Delete their account
Removes all of their comment data, username, and email
address from the site and the database.
@@ -2332,107 +2431,120 @@ address from the site and the database.
data-testid="configure-authContainer"
>
-
- Session settings
-
-
-
-
- Session duration
-
-
-
+
-
-
-
-
-
- Hours
-
-
- Days
-
-
- Weeks
-
-
-
-
- expand_more
-
-
-
+ Session settings
+
-
+
+
+
+
+
+
+ Session duration
+
+
+
+
+
+
+
+
+ Hours
+
+
+ Days
+
+
+ Weeks
+
+
+
+
+ expand_more
+
+
+
+
+
+
+
-
+
Login with email authentication
-
+
Use email authentication login on
@@ -2537,21 +2649,25 @@ address from the site and the database.
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with OpenID Connect
-
+
To learn more:
-
Redirect URI
@@ -2680,8 +2795,8 @@ integration to register for a new account.
/>
-
- Provider name
-
-
- The provider of the OpenID Connect integration. This will be used when the name of the provider
-needs to be displayed, e.g. “Log in with <Facebook>”.
-
-
+
+ Provider name
+
+
+ The provider of the OpenID Connect integration. This will be used when the name of the provider
+needs to be displayed, e.g. “Log in with <Facebook>”.
+
+
+
Client secret
@@ -2810,19 +2937,23 @@ needs to be displayed, e.g. “Log in with <Facebook>”.
-
- Issuer
-
-
- After entering your Issuer information, click the Discover button to have Coral complete
+
+ Issuer
+
+
+ After entering your Issuer information, click the Discover button to have Coral complete
the remaining fields. You may also enter the information manually.
-
+
+
@@ -2846,8 +2977,8 @@ the remaining fields. You may also enter the information manually.
/>
Use OpenID Connect login on
@@ -3015,21 +3158,25 @@ the remaining fields. You may also enter the information manually.
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with Single Sign On
-
+
Key
@@ -3156,7 +3305,7 @@ integration to register for a new account.
KEY GENERATED AT:
Invalid Date
@@ -3174,15 +3323,15 @@ Invalid Date
warning
When regenerating a key, tokens signed with the previous key will be honored for 30 days.
Use Single Sign On login on
@@ -3265,21 +3414,25 @@ Invalid Date
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with Google
-
+
To enable the integration with Google Authentication you need
to create and set up a web application. For more information visit:
@@ -3383,14 +3538,11 @@ to create and set up a web application. For more information visit:
.
-
Redirect URI
@@ -3410,8 +3562,8 @@ to create and set up a web application. For more information visit:
/>
Client secret
@@ -3506,10 +3662,10 @@ to create and set up a web application. For more information visit:
Use Google login on
@@ -3573,21 +3729,25 @@ to create and set up a web application. For more information visit:
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
-
+
Login with Facebook
-
+
To enable the integration with Facebook Authentication,
you need to create and set up a web application.
@@ -3692,14 +3854,11 @@ For more information visit:
.
-
Redirect URI
@@ -3719,8 +3878,8 @@ For more information visit:
/>
Client secret
@@ -3815,10 +3978,10 @@ For more information visit:
Use Facebook login on
@@ -3882,21 +4045,25 @@ For more information visit:
-
- Registration
-
-
- Allow users that have not signed up before with this authentication
-integration to register for a new account.
-
+
+ Registration
+
+
+ Allow users that have not signed up before with this authentication
+integration to register for a new account.
+
+
+
+
-
- Language
-
-
- Choose the language for your Coral community.
-
-
-
-
+
+
- English
-
-
+ English
+
+
+ Português brasileiro
+
+
+ Español
+
+
+ Deutsch
+
+
+ Nederlands
+
+
+ Dansk
+
+
+
- Português brasileiro
-
-
- Español
-
-
- Deutsch
-
-
- Nederlands
-
-
- Dansk
-
-
-
-
- expand_more
-
+
+ expand_more
+
+
-
+
-
- Sitewide commenting
-
-
+
+ Sitewide commenting
+
+
+
+
+
+
- Open or close comment streams for new comments sitewide.
+
+ Open or close comment streams for new comments sitewide.
When new comments are turned off, new comments cannot be
submitted, but existing comments can continue to receive
reactions, be reported, and be shared.
-
-
-
+
- Enable new comments sitewide
-
-
-
-
-
+
+
-
- On - Comment streams opened for new comments
-
+
+
+
+ On - Comment streams opened for new comments
+
+
+
+
+
+
+
+ Off - Comment streams closed for new comments
+
+
+
+
+
+
+
+
+ Sitewide closed comments message
+
+ Write a message that will be displayed when comment streams are closed sitewide
+
-
-
-
- Off - Comment streams closed for new comments
-
-
-
-
- Sitewide closed comments message
-
-
- Write a message that will be displayed when comment streams are closed sitewide
-
-
-
-
-
-
- Community guidelines summary
-
-
+
- Show community guidelines summary
-
-
-
-
-
-
- On
-
-
-
-
-
-
-
- Off
-
-
-
-
-
-
-
Community guidelines summary
-
-
+
+
+
+
+
+
- This will appear above the comments sitewide.
+
+ Show community guidelines summary
+
+
+
+
+
+
+ On
+
+
+
+
+
+
+
+ Off
+
+
+
+
+
+
+
+
+ Community guidelines summary
+
+
+ This will appear above the comments sitewide.
You can format the text using Markdown.
More information on how to use Markdown
-
+ here
+
+ .
+
+
+
- here
-
- .
-
-
-
-
-
+
+
+
+
-
- Comment length
-
+
+
+
+
- Set minimum and maximum comment length requirements.
+
+ Set minimum and maximum comment length requirements.
Blank spaces at the beginning and the end of a comment will be trimmed.
-
-
-
- Limit comment length
-
-
-
-
-
- Minimum comment length
-
+
-
-
- Maximum comment length
-
-
+
+ Minimum comment length
+
-
-
-
-
-
-
- Comment editing
-
-
-
- Set a limit on how long commenters have to edit their comments sitewide.
-Edited comments are marked as (Edited) on the comment stream and the
-moderation panel.
-
-
-
- Comment edit timeframe
-
-
-
-
-
-
-
-
- Seconds
-
-
- Minutes
-
-
- Hours
-
-
-
-
- expand_more
-
-
-
-
-
-
-
-
-
- Closing comment streams
-
-
-
- Set comment streams to close after a defined period of time after a story’s publication
-
-
-
- Close comments automatically
-
-
-
-
-
-
- On
-
-
-
-
-
-
-
- Off
-
-
-
-
-
-
-
- Close comments after
-
-
-
-
-
-
-
-
- Hour
-
-
- Day
-
-
- Week
-
-
-
-
- expand_more
-
-
-
-
-
-
-
-
-
- Closed comment stream message
-
-
-
- Write a message to appear when a story is closed for commenting.
-
-
-
-
-
-
-
-
- Reactions
-
-
-
- Allow your community to engage with one another and express themselves
-with one-click reactions. By default, Coral allows commenters to "Respect"
-each other's comments.
-
-
-
-
-
+
- Reaction label
+
+ Characters
+
+
+
+
+
+
+
+ Maximum comment length
+
+
+
+
+
+
+
+
+
+
+ Comment editing
+
+
+
+
+
+
+
+ Set a limit on how long commenters have to edit their comments sitewide.
+Edited comments are marked as (Edited) on the comment stream and the
+moderation panel.
+
+
+
+ Comment edit timeframe
+
+
+
+
+
+
+
+
+ Seconds
+
+
+ Minutes
+
+
+ Hours
+
+
+
+
+ expand_more
+
+
+
+
+
+
+
+
+
+
+
+
+ Closing comment streams
+
+
+
+
+
+
+
+ Set comment streams to close after a defined period of time after a story’s publication
+
+
+
+ Close comments automatically
+
+
+
+
+
+
+ On
+
+
+
+
+
+
+ Off
+
+
+
+
+
+
+
+ Close comments after
+
+
+
+
+
+
+
+
+ Hour
+
+
+ Day
+
+
+ Week
+
+
+
+
+ expand_more
+
+
+
+
+
+
+
+
+
+
+
+
+ Closed comment stream message
+
+
+
+
+
+
+
+ Write a message to appear when a story is closed for commenting.
+
+
+
+
+
+
+
+
+
+
+
+
+ Allow your community to engage with one another and express themselves
+with one-click reactions. By default, Coral allows commenters to "Respect"
+each other's comments.
+
+
+
+
+ Reaction label
+
+
@@ -895,48 +995,48 @@ each other's comments.
/>
-
+
+
-
- Preview
-
-
-
- Reaction
-
-
-
+ Preview
+
+
+
+ Reaction
+
+
+
+ Active reaction label
+
-
- Active reaction label
-
@@ -954,48 +1054,48 @@ each other's comments.
/>
-
+
+
-
- Preview
-
-
-
- reacted
-
-
-
+ Preview
+
+
+
+ reacted
+
+
+
+ Sort label
+
-
- Sort label
-
@@ -1013,90 +1113,97 @@ each other's comments.
/>
-
+
+
-
+
+
- Preview
-
-
+
-
- Sort by
-
+
+ Reactions
+
+
+
-
-
- Reactions
-
-
-
-
-
- expand_more
-
-
+ expand_more
+
-
+
-
+
-
- Staff member badge
-
-
+
+ Staff member badge
+
+
+
+
+
+
- Show a custom badge for staff members of your organization. This badge
+
+ Show a custom badge for staff members of your organization. This badge
appears on the comment stream and in the admin interface.
-
-
+
+
+ Badge text
+
-
- Badge text
-
@@ -1114,23 +1221,23 @@ appears on the comment stream and in the admin interface.
/>
-
+
+
-
- Preview
-
-
- Staff
-
-
+ Preview
+
+
+ Staff
+
-
+
diff --git a/src/core/client/admin/test/configure/__snapshots__/moderation.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/moderation.spec.tsx.snap
index 643bc1e0c..3e4452f79 100644
--- a/src/core/client/admin/test/configure/__snapshots__/moderation.spec.tsx.snap
+++ b/src/core/client/admin/test/configure/__snapshots__/moderation.spec.tsx.snap
@@ -95,8 +95,8 @@ exports[`renders configure moderation 1`] = `
className="Box-root HorizontalGutter-root HorizontalGutter-double"
>
-
- Pre-moderation
-
+
+
+
+
- When pre-moderation is turned on, comments will not be published unless
+
+ When pre-moderation is turned on, comments will not be published unless
approved by a moderator.
-
-
-
+
- Pre-moderate all comments sitewide
-
-
-
-
-
-
+
- Pre-moderate comments containing links sitewide
-
-
-
- Recent history
-
+
+
+ Recent history
+
+
+
+
+
-
- Recent comment history time period
-
-
- Amount of time to calculate a commenter's rejection rate.
-
-
-
+
+ Recent comment history time period
+
+
+ Amount of time to calculate a commenter's rejection rate.
+
-
- Days
-
-
-
-
-
+
+
+
+ Days
+
+
+
+
- Recent history filter
-
-
- Prevents repeat offenders from publishing comments without approval.
+
+
+ Recent history filter
+
+
+ Prevents repeat offenders from publishing comments without approval.
When a commenter's rejection rate is above the threshold, their
comments are sent to Pending for moderator approval. This does not
apply to Staff comments.
-
-
-
-
-
+
+
+
-
- On
-
+
+
+
+ On
+
+
+
+
+
+
+
+ Off
+
+
+
+
+
+
+
+
+ Rejection rate threshold
+
+ Rejected comments ÷ (rejected comments + published comments)
+over the timeframe above, as a percentage. It does not include
+comments pending for toxicity, spam or pre-moderation.
+
-
-
-
- Off
-
-
+
+
+
+ %
+
+
+
-
-
- Rejection rate threshold
-
-
- Rejected comments ÷ (rejected comments + published comments)
-over the timeframe above, as a percentage. It does not include
-comments pending for toxicity, spam or pre-moderation.
-
-
-
-
- Toxic comment filter
-
-
- Using the Perspective API, the Toxic Comment filter warns users
-when comments exceed the predefined toxicity threshold.
-Comments with a toxicity score above the threshold
-
-
- will not be published
-
- and are placed in
-the
-
- Pending Queue for review by a moderator
-
- .
-If approved by a moderator, the comment will be published.
-
-
+
Toxic comment filter
-
-
-
+
+
-
- Toxicity threshold
-
- This value can be set a percentage between 0 and 100. This number represents the likelihood that a
-comment is toxic, according to Perspective API. By default the threshold is set to 80%.
+ Using the Perspective API, the Toxic Comment filter warns users
+when comments exceed the predefined toxicity threshold.
+Comments with a toxicity score above the threshold
+
+
+ will not be published
+
+ and are placed in
+the
+
+ Pending Queue for review by a moderator
+
+ .
+If approved by a moderator, the comment will be published.
-
-
-
-
+
+
+
+
+
+ Toxicity threshold
+
+
+ This value can be set a percentage between 0 and 100. This number represents the likelihood that a
+comment is toxic, according to Perspective API. By default the threshold is set to 80%.
-
-
-
-
- Toxicity model
-
-
- Choose your Perspective Model. The default is TOXICITY.
-You can find out more about model choices
-
- here
-
- .
-
-
-
-
-
- Allow Google to store comment data
-
-
+
+ Toxicity model
+
+
+ Choose your Perspective Model. The default is TOXICITY.
+You can find out more about model choices
+
+ here
+
+ .
+
+
+
+
+
- Stored comments will be used for future research and community model building purposes to
+
+
+ Allow Google to store comment data
+
+
+ Stored comments will be used for future research and community model building purposes to
improve the API over time.
-
-
+
+
-
-
-
-
-
- API key
-
+
-
-
-
+
+ For additional information on how to set up the Perspective Toxic Comment Filter please visit:
+
+
-
+
+
+
+
+ API key
+
+
+
+
+
- visibility
-
+
+ visibility
+
+
-
-
-
- Custom endpoint
-
-
- By default the endpoint is set to https://commentanalyzer.googleapis.com/v1alpha1. You may override this here.
-
-
+
+ Custom endpoint
+
+
+ By default the endpoint is set to https://commentanalyzer.googleapis.com/v1alpha1. You may override this here.
+
+
-
+
-
- Spam detection filter
-
-
- The Akismet API filter warns users when a comment is determined likely
-to be spam. Comments that Akismet thinks are spam will not be published
-and are placed in the Pending Queue for review by a moderator.
-If approved by a moderator, the comment will be published.
-
-
+
Spam detection filter
-
-
-
-
+
+
+
-
- API key
-
-
+
-
-
+ Spam detection filter
+
+
-
+
- visibility
-
+
+ On
+
+
+
+
+
+
+
+ Off
+
+
+
+
+
+
+
-
-
+
diff --git a/src/core/client/admin/test/configure/__snapshots__/organization.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/organization.spec.tsx.snap
index 76944882d..e4b42cbc8 100644
--- a/src/core/client/admin/test/configure/__snapshots__/organization.spec.tsx.snap
+++ b/src/core/client/admin/test/configure/__snapshots__/organization.spec.tsx.snap
@@ -95,8 +95,8 @@ exports[`renders configure organization 1`] = `
className="Box-root HorizontalGutter-root HorizontalGutter-double"
>
+
+
+ Organization name
+
+
+
+
+
-
- Organization name
-
Your organization name will appear on emails sent by Coral to your community and organization members.
+
+
+ Organization email
+
+
+
+
+
-
- Organization email
-
This email address will be used as in emails and across the platform
for community members to get in touch with the organization should
@@ -185,67 +203,82 @@ they have any questions about the status of their accounts or
moderation questions.
+
+
+ Organization URL
+
+
+
+
+
-
- Organization URL
-
Your organization url will appear on emails sent by Coral to your community and organization members.
diff --git a/src/core/client/admin/test/configure/__snapshots__/wordList.spec.tsx.snap b/src/core/client/admin/test/configure/__snapshots__/wordList.spec.tsx.snap
index 597833a33..9f15935c1 100644
--- a/src/core/client/admin/test/configure/__snapshots__/wordList.spec.tsx.snap
+++ b/src/core/client/admin/test/configure/__snapshots__/wordList.spec.tsx.snap
@@ -95,8 +95,8 @@ exports[`renders configure wordList 1`] = `
className="Box-root HorizontalGutter-root HorizontalGutter-double"
>
-
- Banned words and phrases
-
+
+
+ Banned words and phrases
+
+
+
+
+
-
- Comments containing a word or phrase in the banned words list are
-
- automatically rejected and are not published
-
- .
-
-
- Banned word list
-
- Separate banned words or phrases with a new line. Words/phrases are not case sensitive.
+ Comments containing a word or phrase in the banned words list are
+
+ automatically rejected and are not published
+
+ .
-
+
+
+
+ Banned word list
+
+
+ Separate banned words or phrases with a new line. Words/phrases are not case sensitive.
+
+
-
- Suspect words and phrases
-
+
+
+ Suspect words and phrases
+
+
+
+
+
-
- Comments containing a word or phrase in the Suspect Words List
-are
-
- placed into the Reported Queue for moderator review and are
-published (if comments are not pre-moderated).
-
-
-
- Suspect word list
-
- Separate suspect words or phrases with a new line. Words/phrases are not case sensitive.
+ Comments containing a word or phrase in the Suspect Words List
+are
+
+ placed into the Reported Queue for moderator review and are
+published (if comments are not pre-moderated).
+
-
+
+
+
+ Suspect word list
+
+
+ Separate suspect words or phrases with a new line. Words/phrases are not case sensitive.
+
+
history
-
-
-
Your Decision History
@@ -39,34 +36,32 @@ exports[`loads more 1`] = `
>
- check
+ check_circled
-
Approved comment by
-
+
dany
-
+
-
-
- 2018-11-29T16:01:51.897Z
-
-
+ 2018-11-29T16:01:51.897Z
+
@@ -103,34 +98,32 @@ exports[`loads more 1`] = `
>
cancel
-
Rejected comment by
-
+
dany
-
+
-
-
- 2018-11-29T16:01:45.644Z
-
-
+ 2018-11-29T16:01:45.644Z
+
@@ -167,34 +160,32 @@ exports[`loads more 1`] = `
>
- check
+ check_circled
-
Approved comment by
-
+
dany
-
+
-
-
- 2018-11-29T16:01:42.060Z
-
-
+ 2018-11-29T16:01:42.060Z
+
@@ -234,15 +225,12 @@ exports[`opens popover when clicked on button showing loading state 1`] = `
>
history
-
-
-
Your Decision History
@@ -266,15 +254,12 @@ exports[`render popover content 1`] = `
>
history
-
-
-
Your Decision History
@@ -296,34 +281,32 @@ exports[`render popover content 1`] = `
>
- check
+ check_circled
-
Approved comment by
-
+
addy
-
+
-
-
- 2018-11-29T16:01:51.897Z
-
-
+ 2018-11-29T16:01:51.897Z
+
@@ -360,34 +343,32 @@ exports[`render popover content 1`] = `
>
cancel
-
Rejected comment by
-
+
addy
-
+
-
-
- 2018-11-29T16:01:45.644Z
-
-
+ 2018-11-29T16:01:45.644Z
+
diff --git a/src/core/client/admin/test/moderate/__snapshots__/regularQueue.spec.tsx.snap b/src/core/client/admin/test/moderate/__snapshots__/regularQueue.spec.tsx.snap
index 6c7327d41..d621b7f5f 100644
--- a/src/core/client/admin/test/moderate/__snapshots__/regularQueue.spec.tsx.snap
+++ b/src/core/client/admin/test/moderate/__snapshots__/regularQueue.spec.tsx.snap
@@ -34,7 +34,7 @@ exports[`approves comment in reported queue: dangling 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -85,54 +85,68 @@ exports[`approves comment in reported queue: dangling 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -156,9 +170,9 @@ exports[`approves comment in reported queue: dangling 1`] = `
-
@@ -276,7 +287,7 @@ exports[`rejects comment in reported queue: dangling 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -327,54 +338,68 @@ exports[`rejects comment in reported queue: dangling 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -398,9 +423,9 @@ exports[`rejects comment in reported queue: dangling 1`] = `
-
@@ -515,7 +537,7 @@ exports[`renders reported queue with comments 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -566,54 +588,68 @@ exports[`renders reported queue with comments 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -637,9 +673,9 @@ exports[`renders reported queue with comments 1`] = `
-
@@ -741,7 +774,7 @@ exports[`renders reported queue with comments 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Ngoc
@@ -792,54 +825,68 @@ exports[`renders reported queue with comments 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Offensive
@@ -863,9 +910,9 @@ exports[`renders reported queue with comments 1`] = `
-
@@ -983,7 +1027,7 @@ exports[`renders reported queue with comments 2`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -1034,54 +1078,68 @@ exports[`renders reported queue with comments 2`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -1105,9 +1163,9 @@ exports[`renders reported queue with comments 2`] = `
-
@@ -1209,7 +1264,7 @@ exports[`renders reported queue with comments 2`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Ngoc
@@ -1260,54 +1315,68 @@ exports[`renders reported queue with comments 2`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Offensive
@@ -1331,9 +1400,9 @@ exports[`renders reported queue with comments 2`] = `
-
@@ -1441,7 +1507,7 @@ exports[`renders reported queue with comments and load more 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Max
@@ -1492,54 +1558,68 @@ exports[`renders reported queue with comments and load more 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Pre-mod
Offensive
@@ -1566,7 +1646,7 @@ exports[`renders reported queue with comments and load more 1`] = `
Spam
@@ -1581,9 +1661,9 @@ exports[`renders reported queue with comments and load more 1`] = `
-
diff --git a/src/core/client/admin/test/moderate/__snapshots__/rejectedQueue.spec.tsx.snap b/src/core/client/admin/test/moderate/__snapshots__/rejectedQueue.spec.tsx.snap
index 5c35c0b48..63a2d70bd 100644
--- a/src/core/client/admin/test/moderate/__snapshots__/rejectedQueue.spec.tsx.snap
+++ b/src/core/client/admin/test/moderate/__snapshots__/rejectedQueue.spec.tsx.snap
@@ -34,7 +34,7 @@ exports[`approves comment in rejected queue: dangling 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -85,54 +85,68 @@ exports[`approves comment in rejected queue: dangling 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -156,9 +170,9 @@ exports[`approves comment in rejected queue: dangling 1`] = `
-
@@ -273,7 +284,7 @@ exports[`renders rejected queue with comments 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -324,54 +335,68 @@ exports[`renders rejected queue with comments 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Spam
@@ -395,9 +420,9 @@ exports[`renders rejected queue with comments 1`] = `
-
@@ -499,7 +521,7 @@ exports[`renders rejected queue with comments 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Ngoc
@@ -550,54 +572,68 @@ exports[`renders rejected queue with comments 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Offensive
@@ -621,9 +657,9 @@ exports[`renders rejected queue with comments 1`] = `
-
@@ -731,7 +764,7 @@ exports[`renders rejected queue with comments and load more 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Max
@@ -782,54 +815,68 @@ exports[`renders rejected queue with comments and load more 1`] = `
-
-
- Story
-
- :
-
+ Comment On
+
+
+ :
+
+
+
+
Offensive
@@ -851,7 +898,7 @@ exports[`renders rejected queue with comments and load more 1`] = `
Spam
@@ -866,9 +913,9 @@ exports[`renders rejected queue with comments and load more 1`] = `
-
diff --git a/src/core/client/admin/test/moderate/__snapshots__/searchBar.spec.tsx.snap b/src/core/client/admin/test/moderate/__snapshots__/searchBar.spec.tsx.snap
index 03bc2c80f..e3fa888bb 100644
--- a/src/core/client/admin/test/moderate/__snapshots__/searchBar.spec.tsx.snap
+++ b/src/core/client/admin/test/moderate/__snapshots__/searchBar.spec.tsx.snap
@@ -56,7 +56,7 @@ exports[`all stories active search with no results 1`] = `
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
- placeholder="Use quotation marks around each search term (e.g. “team”, “St. Louis”)"
+ placeholder="search by story title, author, url, id, etc."
spellCheck={false}
value=""
/>
@@ -174,9 +174,9 @@ exports[`all stories active search with too many results 1`] = `
- arrow_forward
+ keyboard_arrow_right
diff --git a/src/core/client/admin/test/moderate/__snapshots__/singleComment.spec.tsx.snap b/src/core/client/admin/test/moderate/__snapshots__/singleComment.spec.tsx.snap
index 5f8208278..7d7a66aff 100644
--- a/src/core/client/admin/test/moderate/__snapshots__/singleComment.spec.tsx.snap
+++ b/src/core/client/admin/test/moderate/__snapshots__/singleComment.spec.tsx.snap
@@ -21,7 +21,7 @@ exports[`approves single comment 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -72,34 +72,43 @@ exports[`approves single comment 1`] = `
-
@@ -107,7 +116,7 @@ exports[`approves single comment 1`] = `
className="Box-root Flex-root Flex-flex Flex-itemGutter gutter"
>
Spam
@@ -122,9 +131,9 @@ exports[`approves single comment 1`] = `
-
@@ -229,7 +235,7 @@ exports[`rejects single comment 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -280,34 +286,43 @@ exports[`rejects single comment 1`] = `
-
@@ -315,7 +330,7 @@ exports[`rejects single comment 1`] = `
className="Box-root Flex-root Flex-flex Flex-itemGutter gutter"
>
Spam
@@ -330,9 +345,9 @@ exports[`rejects single comment 1`] = `
-
@@ -472,7 +484,7 @@ exports[`renders single comment view 1`] = `
className="Box-root Flex-root Flex-flex Flex-alignCenter"
>
Isabelle
@@ -523,34 +535,43 @@ exports[`renders single comment view 1`] = `
-
@@ -558,7 +579,7 @@ exports[`renders single comment view 1`] = `
className="Box-root Flex-root Flex-flex Flex-itemGutter gutter"
>
Spam
@@ -573,9 +594,9 @@ exports[`renders single comment view 1`] = `
-
diff --git a/src/core/client/admin/test/stories/__snapshots__/stories.spec.tsx.snap b/src/core/client/admin/test/stories/__snapshots__/stories.spec.tsx.snap
index 22040f178..8f9158d69 100644
--- a/src/core/client/admin/test/stories/__snapshots__/stories.spec.tsx.snap
+++ b/src/core/client/admin/test/stories/__snapshots__/stories.spec.tsx.snap
@@ -14,103 +14,111 @@ exports[`renders empty stories 1`] = `
-
- Search
-
-
-
+ Search
+
+
-
-
+
-
- search
-
-
+
+ search
+
+
+
-
-
+
+
-
- Show Me
-
-
-
-
+
+
- All Stories
-
-
+ All Stories
+
+
+ Open Stories
+
+
+ Closed Stories
+
+
+
- Open Stories
-
-
- Closed Stories
-
-
-
-
- expand_more
-
+
+ expand_more
+
+
-
+
-
- Search
-
-
-
+ Search
+
+
-
-
+
-
- search
-
-
+
+ search
+
+
+
-
-
+
+
-
- Show Me
-
-
-
-
+
+
- All Stories
-
-
+ All Stories
+
+
+ Open Stories
+
+
+ Closed Stories
+
+
+
- Open Stories
-
-
- Closed Stories
-
-
-
-
- expand_more
-
+
+ expand_more
+
+
-
+
{
text: string;
+ size?: "small" | "medium" | "large";
}
interface State {
@@ -39,11 +40,11 @@ class CopyButton extends React.Component {
};
public render() {
- const { text, ...rest } = this.props;
+ const { text, size, ...rest } = this.props;
const { copied } = this.state;
return (
-
+
{copied ? (
Copied!
diff --git a/src/core/client/stream/tabs/Configure/Configure.tsx b/src/core/client/stream/tabs/Configure/Configure.tsx
index f52093e1d..52c905544 100644
--- a/src/core/client/stream/tabs/Configure/Configure.tsx
+++ b/src/core/client/stream/tabs/Configure/Configure.tsx
@@ -2,7 +2,7 @@ import React, { FunctionComponent } from "react";
import { PropTypesOf } from "coral-framework/types";
import UserBoxContainer from "coral-stream/common/UserBox";
-import { HorizontalGutter } from "coral-ui/components";
+import { HorizontalGutter } from "coral-ui/components/v2";
import ConfigureStreamContainer from "./ConfigureStream";
import HorizontalRule from "./HorizontalRule";
diff --git a/src/core/client/ui/components/Dropdown/Button.css b/src/core/client/ui/components/Dropdown/Button.css
index c4128bfc0..fe87b877a 100644
--- a/src/core/client/ui/components/Dropdown/Button.css
+++ b/src/core/client/ui/components/Dropdown/Button.css
@@ -3,7 +3,7 @@
display: flex;
justify-content: space-between;
align-items: center;
- padding: var(--spacing-2);
+ padding: var(--v2-spacing-2);
width: 100%;
text-align: left;
line-height: 1;
@@ -34,13 +34,13 @@
justify-content: baseline;
align-items: center;
color: var(--palette-grey-main);
- margin-right: var(--spacing-2);
+ margin-right: var(--v2-spacing-2);
}
.iconAfter {
display: flex;
align-items: center;
justify-content: baseline;
- margin-left: var(--spacing-2);
+ margin-left: var(--v2-spacing-2);
text-decoration: unset;
}
.iconOpenInNew {
@@ -49,5 +49,5 @@
}
.blankAdornment {
- padding-right: var(--spacing-6);
+ padding-right: var(--v2-spacing-6);
}
diff --git a/src/core/client/ui/components/Marker/Marker.css b/src/core/client/ui/components/Marker/Marker.css
index cbed39ba8..79482d206 100644
--- a/src/core/client/ui/components/Marker/Marker.css
+++ b/src/core/client/ui/components/Marker/Marker.css
@@ -1,5 +1,6 @@
.root {
composes: markerText from "coral-ui/shared/typography.css";
+
color: var(--palette-error-main);
border: 1px solid currentColor;
border-radius: 20px;
diff --git a/src/core/client/ui/components/Typography/Typography.css b/src/core/client/ui/components/Typography/Typography.css
index f292d0229..cc52d79f2 100644
--- a/src/core/client/ui/components/Typography/Typography.css
+++ b/src/core/client/ui/components/Typography/Typography.css
@@ -144,4 +144,10 @@
.inputLabel {
composes: inputLabel from "coral-ui/shared/typography.css";
-}
\ No newline at end of file
+}
+
+/* V2 Typography */
+
+.bodyCommentV2 {
+ composes: bodyCommentV2 from "coral-ui/shared/typography.css";
+}
diff --git a/src/core/client/ui/components/Typography/Typography.tsx b/src/core/client/ui/components/Typography/Typography.tsx
index 0d74317be..f9dabdbc4 100644
--- a/src/core/client/ui/components/Typography/Typography.tsx
+++ b/src/core/client/ui/components/Typography/Typography.tsx
@@ -27,7 +27,9 @@ type Variant =
| "fieldDescription"
| "inputLabel"
| "detail"
- | "timestamp";
+ | "timestamp"
+ // V2
+ | "bodyCommentV2";
// Based on Typography Component of Material UI.
// https://github.com/mui-org/material-ui/blob/303199d39b42a321d28347d8440d69166f872f27/packages/material-ui/src/Typography/Typography.js
@@ -62,7 +64,9 @@ interface Props extends PropTypesOf {
| "error"
| "errorDark"
| "textDark"
- | "success";
+ | "success"
+ // V2
+ | "textPrimaryV2";
/**
* The container used for the root node.
* Either a string to use a DOM element, a component, or an element.
@@ -171,6 +175,8 @@ Typography.defaultProps = {
timestamp: "span",
inputLabel: "label",
detail: "p",
+ // V2
+ bodyCommentV2: "p",
},
noWrap: false,
paragraph: false,
diff --git a/src/core/client/ui/components/v2/AppBar/AppBar.css b/src/core/client/ui/components/v2/AppBar/AppBar.css
new file mode 100644
index 000000000..1783055e2
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/AppBar.css
@@ -0,0 +1,18 @@
+.root {
+ background-color: var(--v2-palette-main-nav-background-default);
+ border-bottom: 1px solid var(--v2-palette-divider);
+}
+
+.container {
+ max-width: 1280px;
+ margin: 0 auto;
+ height: calc(8 * var(--mini-unit));
+ box-sizing: border-box;
+}
+
+.gutterBegin {
+ padding-left: calc(2 * var(--mini-unit));
+}
+.gutterEnd {
+ padding-right: calc(2 * var(--mini-unit));
+}
diff --git a/src/core/client/ui/components/v2/AppBar/AppBar.mdx b/src/core/client/ui/components/v2/AppBar/AppBar.mdx
new file mode 100644
index 000000000..a0b6c5a65
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/AppBar.mdx
@@ -0,0 +1,37 @@
+---
+name: AppBar
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+
+import { AppBar, Begin, End, Navigation, NavigationItem, Divider } from "./";
+import { Logo } from "../Brand";
+import Flex from "../Flex";
+import Icon from "../Icon";
+import BaseButton from "../BaseButton";
+
+# AppBar
+
+## Basic usage
+
+
+
+
+
+
+ Home
+ Team
+
+
+
+
+ history
+
+
+
+ account_box
+
+
+
+
diff --git a/src/core/client/ui/components/v2/AppBar/AppBar.spec.tsx b/src/core/client/ui/components/v2/AppBar/AppBar.spec.tsx
new file mode 100644
index 000000000..a59d1c536
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/AppBar.spec.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import AppBar from "./AppBar";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "child",
+ gutterBegin: true,
+ gutterEnd: true,
+ className: "custom",
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/AppBar.tsx b/src/core/client/ui/components/v2/AppBar/AppBar.tsx
new file mode 100644
index 000000000..2fa21fbc1
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/AppBar.tsx
@@ -0,0 +1,38 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { Flex } from "coral-ui/components";
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./AppBar.css";
+
+interface Props {
+ children?: React.ReactNode;
+ className?: string;
+ gutterBegin?: boolean;
+ gutterEnd?: boolean;
+ classes: typeof styles;
+}
+
+const AppBar: FunctionComponent = ({
+ gutterBegin,
+ gutterEnd,
+ className,
+ children,
+ classes,
+ ...rest
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default withStyles(styles)(AppBar);
diff --git a/src/core/client/ui/components/v2/AppBar/Begin.css b/src/core/client/ui/components/v2/AppBar/Begin.css
new file mode 100644
index 000000000..365d8e488
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Begin.css
@@ -0,0 +1,3 @@
+.root {
+ flex-grow: 1;
+}
diff --git a/src/core/client/ui/components/v2/AppBar/Begin.spec.tsx b/src/core/client/ui/components/v2/AppBar/Begin.spec.tsx
new file mode 100644
index 000000000..442d0b3ec
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Begin.spec.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import End from "./End";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "children",
+ className: "custom",
+ itemGutter: true,
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/Begin.tsx b/src/core/client/ui/components/v2/AppBar/Begin.tsx
new file mode 100644
index 000000000..08732cfc0
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Begin.tsx
@@ -0,0 +1,27 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { Flex } from "coral-ui/components";
+import { withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./Begin.css";
+
+interface Props extends PropTypesOf {
+ children?: React.ReactNode;
+ className?: string;
+ classes: typeof styles;
+}
+
+const Begin: FunctionComponent = ({
+ className,
+ children,
+ classes,
+ ...rest
+}) => (
+
+ {children}
+
+);
+
+export default withStyles(styles)(Begin);
diff --git a/src/core/client/ui/components/v2/AppBar/Divider.css b/src/core/client/ui/components/v2/AppBar/Divider.css
new file mode 100644
index 000000000..1f9f9872f
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Divider.css
@@ -0,0 +1,4 @@
+.root {
+ height: 32px;
+ border-right: 2px solid var(--v2-palette-main-nav-divider);
+}
diff --git a/src/core/client/ui/components/v2/AppBar/Divider.spec.tsx b/src/core/client/ui/components/v2/AppBar/Divider.spec.tsx
new file mode 100644
index 000000000..0489e8451
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Divider.spec.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import Divider from "./Divider";
+
+it("renders correctly", () => {
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/Divider.tsx b/src/core/client/ui/components/v2/AppBar/Divider.tsx
new file mode 100644
index 000000000..0f3c3f9d5
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Divider.tsx
@@ -0,0 +1,17 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Divider.css";
+
+interface Props {
+ className?: string;
+ classes: typeof styles;
+}
+
+const Divider: FunctionComponent = ({ className, classes, ...rest }) => (
+
+);
+
+export default withStyles(styles)(Divider);
diff --git a/src/core/client/ui/components/v2/AppBar/End.css b/src/core/client/ui/components/v2/AppBar/End.css
new file mode 100644
index 000000000..8b4643190
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/End.css
@@ -0,0 +1,4 @@
+.root {
+ flex-grow: 0;
+ flex-shrink: 0;
+}
diff --git a/src/core/client/ui/components/v2/AppBar/End.spec.tsx b/src/core/client/ui/components/v2/AppBar/End.spec.tsx
new file mode 100644
index 000000000..442d0b3ec
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/End.spec.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import End from "./End";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "children",
+ className: "custom",
+ itemGutter: true,
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/End.tsx b/src/core/client/ui/components/v2/AppBar/End.tsx
new file mode 100644
index 000000000..ffc2275ef
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/End.tsx
@@ -0,0 +1,27 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { Flex } from "coral-ui/components";
+import { withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./End.css";
+
+interface Props extends PropTypesOf {
+ children?: React.ReactNode;
+ className?: string;
+ classes: typeof styles;
+}
+
+const End: FunctionComponent = ({
+ classes,
+ className,
+ children,
+ ...rest
+}) => (
+
+ {children}
+
+);
+
+export default withStyles(styles)(End);
diff --git a/src/core/client/ui/components/v2/AppBar/Navigation.css b/src/core/client/ui/components/v2/AppBar/Navigation.css
new file mode 100644
index 000000000..3c1d3b4a8
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Navigation.css
@@ -0,0 +1,11 @@
+.root {
+ height: 100%;
+}
+
+.ul {
+ list-style: none;
+ padding: 0;
+ display: flex;
+ height: 100%;
+ margin: 0;
+}
diff --git a/src/core/client/ui/components/v2/AppBar/Navigation.spec.tsx b/src/core/client/ui/components/v2/AppBar/Navigation.spec.tsx
new file mode 100644
index 000000000..1a3953b98
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Navigation.spec.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import Navigation from "./Navigation";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "children",
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/Navigation.tsx b/src/core/client/ui/components/v2/AppBar/Navigation.tsx
new file mode 100644
index 000000000..8a19567b4
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/Navigation.tsx
@@ -0,0 +1,24 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Navigation.css";
+
+interface Props {
+ className?: string;
+ classes: typeof styles;
+ children?: React.ReactNode;
+}
+
+const Navigation: FunctionComponent = ({
+ children,
+ className,
+ classes,
+}) => (
+
+
+
+);
+
+export default withStyles(styles)(Navigation);
diff --git a/src/core/client/ui/components/v2/AppBar/NavigationItem.css b/src/core/client/ui/components/v2/AppBar/NavigationItem.css
new file mode 100644
index 000000000..c517e483c
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/NavigationItem.css
@@ -0,0 +1,45 @@
+$main-nav-text: var(--v2-colors-mono-100);
+$main-nav-background: var(--v2-colors-pure-white);
+$main-nav-hover-background: var(--v2-colors-coral-200);
+$main-nav-active-background: var(--v2-colors-coral-500);
+$main-nav-active-text: var(--v2-colors-pure-white);
+$main-nav-hover-text: var(--v2-colors-mono-500);
+
+.root {
+}
+
+.anchor {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-3);
+ text-transform: uppercase;
+
+ color: $main-nav-text;
+ height: 100%;
+ display: inline-flex;
+ align-items: center;
+ padding: 0 var(--mini-unit);
+ text-decoration: none;
+
+ &:hover {
+ cursor: pointer;
+ color: $main-nav-hover-text;
+ background-color: $main-nav-hover-background;
+ }
+}
+
+.active {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-3);
+ text-transform: uppercase;
+
+ background-color: $main-nav-active-background;
+ text-decoration: none;
+ color: $main-nav-active-text;
+
+ &:hover {
+ color: $main-nav-active-text;
+ background-color: $main-nav-active-background;
+ }
+}
diff --git a/src/core/client/ui/components/v2/AppBar/NavigationItem.spec.tsx b/src/core/client/ui/components/v2/AppBar/NavigationItem.spec.tsx
new file mode 100644
index 000000000..1f7e58c22
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/NavigationItem.spec.tsx
@@ -0,0 +1,20 @@
+import { noop } from "lodash";
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import NavigationItem from "./NavigationItem";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ href: "/moderate",
+ children: "link",
+ onClick: noop,
+ active: true,
+ className: "custom",
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AppBar/NavigationItem.tsx b/src/core/client/ui/components/v2/AppBar/NavigationItem.tsx
new file mode 100644
index 000000000..b67489475
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/NavigationItem.tsx
@@ -0,0 +1,41 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./NavigationItem.css";
+
+interface Props {
+ children: React.ReactNode;
+ href: string;
+ className?: string;
+ active?: boolean;
+ onClick?: React.EventHandler;
+ classes: typeof styles;
+}
+
+const NavigationItem: FunctionComponent = ({
+ className,
+ active,
+ href,
+ onClick,
+ children,
+ classes,
+ ...rest
+}) => {
+ return (
+
+
+ {children}
+
+
+ );
+};
+
+export default withStyles(styles)(NavigationItem);
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/AppBar.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/AppBar.spec.tsx.snap
new file mode 100644
index 000000000..cef384323
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/AppBar.spec.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ child
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/Begin.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/Begin.spec.tsx.snap
new file mode 100644
index 000000000..7f8ca63d8
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/Begin.spec.tsx.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ children
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/Divider.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/Divider.spec.tsx.snap
new file mode 100644
index 000000000..722ea5f94
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/Divider.spec.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/End.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/End.spec.tsx.snap
new file mode 100644
index 000000000..7f8ca63d8
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/End.spec.tsx.snap
@@ -0,0 +1,15 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ children
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/Navigation.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/Navigation.spec.tsx.snap
new file mode 100644
index 000000000..54f9bae45
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/Navigation.spec.tsx.snap
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ children
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/__snapshots__/NavigationItem.spec.tsx.snap b/src/core/client/ui/components/v2/AppBar/__snapshots__/NavigationItem.spec.tsx.snap
new file mode 100644
index 000000000..7ad60ce3d
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/__snapshots__/NavigationItem.spec.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ link
+
+`;
diff --git a/src/core/client/ui/components/v2/AppBar/index.ts b/src/core/client/ui/components/v2/AppBar/index.ts
new file mode 100644
index 000000000..c3ef851d4
--- /dev/null
+++ b/src/core/client/ui/components/v2/AppBar/index.ts
@@ -0,0 +1,6 @@
+export { default as AppBar } from "./AppBar";
+export { default as Begin } from "./Begin";
+export { default as End } from "./End";
+export { default as Navigation } from "./Navigation";
+export { default as NavigationItem } from "./NavigationItem";
+export { default as Divider } from "./Divider";
diff --git a/src/core/client/ui/components/v2/AriaInfo/AriaInfo.css b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.css
new file mode 100644
index 000000000..bca89bafb
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.css
@@ -0,0 +1,10 @@
+.root {
+ position: absolute !important;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
diff --git a/src/core/client/ui/components/v2/AriaInfo/AriaInfo.mdx b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.mdx
new file mode 100644
index 000000000..6cdaf7b62
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.mdx
@@ -0,0 +1,18 @@
+---
+name: AriaInfo
+menu: UI Kit
+---
+
+import { Playground } from "docz";
+import AriaInfo from "./AriaInfo";
+
+# AriaInfo
+
+Renders Text that is only seen by screen readers.
+
+## Basic usage
+
+
+ This can only be seen by screen readers
+ Above this line is a hidden text that you can't see
+
diff --git a/src/core/client/ui/components/v2/AriaInfo/AriaInfo.spec.tsx b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.spec.tsx
new file mode 100644
index 000000000..4b07da123
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.spec.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import AriaInfo from "./AriaInfo";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "This text is only for screen readers",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/AriaInfo/AriaInfo.tsx b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.tsx
new file mode 100644
index 000000000..4ec81e353
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/AriaInfo.tsx
@@ -0,0 +1,36 @@
+import cn from "classnames";
+import React, { AllHTMLAttributes, FunctionComponent, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./AriaInfo.css";
+
+interface Props extends AllHTMLAttributes {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+ component?: string;
+ children: React.ReactNode;
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const AriaInfo: FunctionComponent = props => {
+ const { component, className, classes, forwardRef: ref, ...rest } = props;
+ const Component: React.ComponentType<
+ React.HTMLAttributes & React.ClassAttributes
+ > = component! as any;
+ const rootClassName = cn(classes.root, className);
+ return ;
+};
+
+AriaInfo.defaultProps = {
+ component: "div",
+};
+
+const enhanced = withForwardRef(withStyles(styles)(AriaInfo));
+export type AriaInfoProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/AriaInfo/__snapshots__/AriaInfo.spec.tsx.snap b/src/core/client/ui/components/v2/AriaInfo/__snapshots__/AriaInfo.spec.tsx.snap
new file mode 100644
index 000000000..688492e16
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/__snapshots__/AriaInfo.spec.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ This text is only for screen readers
+
+`;
diff --git a/src/core/client/ui/components/v2/AriaInfo/index.ts b/src/core/client/ui/components/v2/AriaInfo/index.ts
new file mode 100644
index 000000000..7fc32af4c
--- /dev/null
+++ b/src/core/client/ui/components/v2/AriaInfo/index.ts
@@ -0,0 +1 @@
+export { default, AriaInfoProps } from "./AriaInfo";
diff --git a/src/core/client/ui/components/v2/Backdrop/Backdrop.css b/src/core/client/ui/components/v2/Backdrop/Backdrop.css
new file mode 100644
index 000000000..7517851e1
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/Backdrop.css
@@ -0,0 +1,15 @@
+.root {
+ display: none;
+ background: black;
+ position: fixed;
+ /* fix to bottom solves some mobile scrolling issues. */
+ bottom: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.active {
+ display: block;
+ opacity: 0.5;
+}
diff --git a/src/core/client/ui/components/v2/Backdrop/Backdrop.mdx b/src/core/client/ui/components/v2/Backdrop/Backdrop.mdx
new file mode 100644
index 000000000..b1491616c
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/Backdrop.mdx
@@ -0,0 +1,32 @@
+---
+name: Backdrop
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import Container from "react-with-state-props";
+
+import Button from "../Button";
+import Backdrop from "./Backdrop";
+
+# Backdrop
+
+## Basic usage
+
+
+ (
+
+
+ props.setValue(!props.value)}
+ >
+ Toggle
+
+
+ )}
+ />
+
diff --git a/src/core/client/ui/components/v2/Backdrop/Backdrop.spec.tsx b/src/core/client/ui/components/v2/Backdrop/Backdrop.spec.tsx
new file mode 100644
index 000000000..3d4140265
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/Backdrop.spec.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import Backdrop from "./Backdrop";
+
+it("renders correctly", () => {
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("renders correctly when active", () => {
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Backdrop/Backdrop.tsx b/src/core/client/ui/components/v2/Backdrop/Backdrop.tsx
new file mode 100644
index 000000000..b97bb24fd
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/Backdrop.tsx
@@ -0,0 +1,35 @@
+import cn from "classnames";
+import React, { FunctionComponent, HTMLAttributes } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Backdrop.css";
+
+interface Props extends HTMLAttributes {
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ active?: boolean;
+}
+
+const Backdrop: FunctionComponent = ({
+ classes,
+ active,
+ className,
+ children,
+ ...rest
+}) => {
+ const rootClassName = cn(
+ classes.root,
+ {
+ [classes.active]: Boolean(active),
+ },
+ className
+ );
+ return
;
+};
+
+const enhanced = withStyles(styles)(Backdrop);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Backdrop/__snapshots__/Backdrop.spec.tsx.snap b/src/core/client/ui/components/v2/Backdrop/__snapshots__/Backdrop.spec.tsx.snap
new file mode 100644
index 000000000..19d396229
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/__snapshots__/Backdrop.spec.tsx.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
+
+exports[`renders correctly when active 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/Backdrop/index.ts b/src/core/client/ui/components/v2/Backdrop/index.ts
new file mode 100644
index 000000000..e0de8166e
--- /dev/null
+++ b/src/core/client/ui/components/v2/Backdrop/index.ts
@@ -0,0 +1 @@
+export { default } from "./Backdrop";
diff --git a/src/core/client/ui/components/v2/BaseButton/BaseButton.css b/src/core/client/ui/components/v2/BaseButton/BaseButton.css
new file mode 100644
index 000000000..89d7cc80c
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/BaseButton.css
@@ -0,0 +1,43 @@
+.root {
+ /* reset button */
+ user-select: none;
+ font-family: inherit;
+ outline: none;
+ border: none;
+ touch-action: manipulation;
+ padding: 0;
+ margin: 0;
+
+ /* Unify anchor and button. */
+ cursor: pointer;
+ display: inline-block;
+ box-sizing: border-box;
+ text-align: center;
+ text-decoration: none;
+ align-items: flex-start;
+ vertical-align: middle;
+ white-space: nowrap;
+ background: transparent;
+ font-size: inherit;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;
+ -webkit-appearance: none;
+
+ &:disabled {
+ cursor: default;
+ }
+
+ &::-moz-focus-inner {
+ border: 0;
+ }
+
+ &:-moz-focusring {
+ textshadow: 0 0 0 #000;
+ }
+}
+
+.keyboardFocus {
+ @mixin outline;
+}
+
+.mouseHover {
+}
diff --git a/src/core/client/ui/components/v2/BaseButton/BaseButton.mdx b/src/core/client/ui/components/v2/BaseButton/BaseButton.mdx
new file mode 100644
index 000000000..d4dd00669
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/BaseButton.mdx
@@ -0,0 +1,28 @@
+---
+name: BaseButton
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import BaseButton from './BaseButton'
+
+# BaseButton
+
+`BaseButton` strips away browser specific styling and unifies the look of the `button` and the `a` tag.
+It detects a focus that came from the keyboard rather than mouse or touch and styles the button using
+the `className` provided in the `classes.keyboardFocus` property.
+
+When used as a `button` tag the default `type` is set to `button` instead of the standard `submit` in order
+to avoid unintended form submissions.
+
+## Basic usage
+
+ Push Me
+
+
+Instead of an `button` tag, we can render an `a` tag instead:
+
+
+ Push Me
+
+
diff --git a/src/core/client/ui/components/v2/BaseButton/BaseButton.spec.tsx b/src/core/client/ui/components/v2/BaseButton/BaseButton.spec.tsx
new file mode 100644
index 000000000..c0f7176b9
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/BaseButton.spec.tsx
@@ -0,0 +1,24 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import BaseButton from "./BaseButton";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "my-class",
+ children: "Push Me",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders as anchor", () => {
+ const props: PropTypesOf = {
+ anchor: true,
+ children: "Push Me",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/BaseButton/BaseButton.tsx b/src/core/client/ui/components/v2/BaseButton/BaseButton.tsx
new file mode 100644
index 000000000..3e1562908
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/BaseButton.tsx
@@ -0,0 +1,99 @@
+import cn from "classnames";
+import React, {
+ ButtonHTMLAttributes,
+ EventHandler,
+ FocusEvent,
+ FunctionComponent,
+ MouseEvent,
+ Ref,
+ TouchEvent,
+} from "react";
+
+import {
+ withForwardRef,
+ withKeyboardFocus,
+ withMouseHover,
+ withStyles,
+} from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./BaseButton.css";
+
+interface Props extends ButtonHTMLAttributes {
+ /** If set renders an anchor tag instead */
+ anchor?: boolean;
+ href?: string;
+ target?: string;
+ rel?: string;
+
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+
+ type?: "submit" | "reset" | "button";
+
+ // These handlers are passed down by the `withMouseHover` HOC.
+ mouseHover: boolean;
+ onMouseOver: React.EventHandler>;
+ onMouseOut: React.EventHandler>;
+ onTouchEnd: React.EventHandler>;
+
+ // These handlers are passed down by the `withKeyboardFocus` HOC.
+ onFocus: EventHandler>;
+ onBlur: EventHandler>;
+ keyboardFocus: boolean;
+}
+
+/**
+ * A button whose styling is stripped off to a minimum and supports
+ * keyboard focus. It is the base for our other buttons.
+ */
+const BaseButton: FunctionComponent = ({
+ anchor,
+ className,
+ classes,
+ keyboardFocus,
+ mouseHover,
+ forwardRef,
+ type,
+ ...rest
+}) => {
+ let Element: React.ComponentType<
+ React.ButtonHTMLAttributes &
+ React.ClassAttributes
+ > = "button" as any;
+
+ if (anchor) {
+ Element = "a" as any;
+ }
+
+ if (anchor && type) {
+ // eslint-disable-next-line no-console
+ console.warn(
+ "BaseButton used as anchor does not support the `type` property"
+ );
+ } else if (type === undefined) {
+ // Default to button
+ type = "button";
+ }
+
+ const rootClassName = cn(classes.root, className, {
+ [classes.keyboardFocus]: keyboardFocus,
+ [classes.mouseHover]: mouseHover,
+ });
+
+ return (
+
+ );
+};
+
+const enhanced = withForwardRef(
+ withStyles(styles)(withMouseHover(withKeyboardFocus(BaseButton)))
+);
+export type BaseButtonProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/BaseButton/__snapshots__/BaseButton.spec.tsx.snap b/src/core/client/ui/components/v2/BaseButton/__snapshots__/BaseButton.spec.tsx.snap
new file mode 100644
index 000000000..c7f55a935
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/__snapshots__/BaseButton.spec.tsx.snap
@@ -0,0 +1,29 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders as anchor 1`] = `
+
+ Push Me
+
+`;
+
+exports[`renders correctly 1`] = `
+
+ Push Me
+
+`;
diff --git a/src/core/client/ui/components/v2/BaseButton/index.ts b/src/core/client/ui/components/v2/BaseButton/index.ts
new file mode 100644
index 000000000..53e4924d5
--- /dev/null
+++ b/src/core/client/ui/components/v2/BaseButton/index.ts
@@ -0,0 +1 @@
+export { default, BaseButtonProps } from "./BaseButton";
diff --git a/src/core/client/ui/components/v2/Box/Box.css b/src/core/client/ui/components/v2/Box/Box.css
new file mode 100644
index 000000000..647068f01
--- /dev/null
+++ b/src/core/client/ui/components/v2/Box/Box.css
@@ -0,0 +1,240 @@
+.root {
+}
+
+/* Margin */
+
+.ml-1 {
+ margin-left: var(--v2-spacing-1) !important;
+}
+.mr-1 {
+ margin-right: var(--v2-spacing-1) !important;
+}
+.mt-1 {
+ margin-top: var(--v2-spacing-1) !important;
+}
+.mb-1 {
+ margin-bottom: var(--v2-spacing-1) !important;
+}
+
+.ml-2 {
+ margin-left: var(--v2-spacing-2) !important;
+}
+.mr-2 {
+ margin-right: var(--v2-spacing-2) !important;
+}
+.mt-2 {
+ margin-top: var(--v2-spacing-2) !important;
+}
+.mb-2 {
+ margin-bottom: var(--v2-spacing-2) !important;
+}
+
+.ml-3 {
+ margin-left: var(--v2-spacing-3) !important;
+}
+.mr-3 {
+ margin-right: var(--v2-spacing-3) !important;
+}
+.mt-3 {
+ margin-top: var(--v2-spacing-3) !important;
+}
+.mb-3 {
+ margin-bottom: var(--v2-spacing-3) !important;
+}
+
+.ml-4 {
+ margin-left: var(--v2-spacing-4) !important;
+}
+.mr-4 {
+ margin-right: var(--v2-spacing-4) !important;
+}
+.mt-4 {
+ margin-top: var(--v2-spacing-4) !important;
+}
+.mb-4 {
+ margin-bottom: var(--v2-spacing-4) !important;
+}
+
+.ml-5 {
+ margin-left: var(--v2-spacing-5) !important;
+}
+.mr-5 {
+ margin-right: var(--v2-spacing-5) !important;
+}
+.mt-5 {
+ margin-top: var(--v2-spacing-5) !important;
+}
+.mb-5 {
+ margin-bottom: var(--v2-spacing-5) !important;
+}
+
+.ml-6 {
+ margin-left: var(--v2-spacing-6) !important;
+}
+.mr-6 {
+ margin-right: var(--v2-spacing-6) !important;
+}
+.mt-6 {
+ margin-top: var(--v2-spacing-6) !important;
+}
+.mb-6 {
+ margin-bottom: var(--v2-spacing-6) !important;
+}
+
+.ml-7 {
+ margin-left: var(--v2-spacing-7) !important;
+}
+.mr-7 {
+ margin-right: var(--v2-spacing-7) !important;
+}
+.mt-7 {
+ margin-top: var(--v2-spacing-7) !important;
+}
+.mb-7 {
+ margin-bottom: var(--v2-spacing-7) !important;
+}
+
+.ml-8 {
+ margin-left: var(--v2-spacing-8) !important;
+}
+.mr-8 {
+ margin-right: var(--v2-spacing-8) !important;
+}
+.mt-8 {
+ margin-top: var(--v2-spacing-8) !important;
+}
+.mb-8 {
+ margin-bottom: var(--v2-spacing-8) !important;
+}
+
+.ml-9 {
+ margin-left: var(--v2-spacing-9) !important;
+}
+.mr-9 {
+ margin-right: var(--v2-spacing-9) !important;
+}
+.mt-9 {
+ margin-top: var(--v2-spacing-9) !important;
+}
+.mb-9 {
+ margin-bottom: var(--v2-spacing-9) !important;
+}
+
+/* Padding */
+
+.pl-1 {
+ padding-left: var(--v2-spacing-1) !important;
+}
+.pr-1 {
+ padding-right: var(--v2-spacing-1) !important;
+}
+.pt-1 {
+ padding-top: var(--v2-spacing-1) !important;
+}
+.pb-1 {
+ padding-bottom: var(--v2-spacing-1) !important;
+}
+
+.pl-2 {
+ padding-left: var(--v2-spacing-2) !important;
+}
+.pr-2 {
+ padding-right: var(--v2-spacing-2) !important;
+}
+.pt-2 {
+ padding-top: var(--v2-spacing-2) !important;
+}
+.pb-2 {
+ padding-bottom: var(--v2-spacing-2) !important;
+}
+
+.pl-3 {
+ padding-left: var(--v2-spacing-3) !important;
+}
+.pr-3 {
+ padding-right: var(--v2-spacing-3) !important;
+}
+.pt-3 {
+ padding-top: var(--v2-spacing-3) !important;
+}
+.pb-3 {
+ padding-bottom: var(--v2-spacing-3) !important;
+}
+
+.pl-4 {
+ padding-left: var(--v2-spacing-4) !important;
+}
+.pr-4 {
+ padding-right: var(--v2-spacing-4) !important;
+}
+.pt-4 {
+ padding-top: var(--v2-spacing-4) !important;
+}
+.pb-4 {
+ padding-bottom: var(--v2-spacing-4) !important;
+}
+
+.pl-5 {
+ padding-left: var(--v2-spacing-5) !important;
+}
+.pr-5 {
+ padding-right: var(--v2-spacing-5) !important;
+}
+.pt-5 {
+ padding-top: var(--v2-spacing-5) !important;
+}
+.pb-5 {
+ padding-bottom: var(--v2-spacing-5) !important;
+}
+
+.pl-6 {
+ padding-left: var(--v2-spacing-6) !important;
+}
+.pr-6 {
+ padding-right: var(--v2-spacing-6) !important;
+}
+.pt-6 {
+ padding-top: var(--v2-spacing-6) !important;
+}
+.pb-6 {
+ padding-bottom: var(--v2-spacing-6) !important;
+}
+
+.pl-7 {
+ padding-left: var(--v2-spacing-7) !important;
+}
+.pr-7 {
+ padding-right: var(--v2-spacing-7) !important;
+}
+.pt-7 {
+ padding-top: var(--v2-spacing-7) !important;
+}
+.pb-7 {
+ padding-bottom: var(--v2-spacing-7) !important;
+}
+
+.pl-8 {
+ padding-left: var(--v2-spacing-8) !important;
+}
+.pr-8 {
+ padding-right: var(--v2-spacing-8) !important;
+}
+.pt-8 {
+ padding-top: var(--v2-spacing-8) !important;
+}
+.pb-8 {
+ padding-bottom: var(--v2-spacing-8) !important;
+}
+
+.pl-9 {
+ padding-left: var(--v2-spacing-9) !important;
+}
+.pr-9 {
+ padding-right: var(--v2-spacing-9) !important;
+}
+.pt-9 {
+ padding-top: var(--v2-spacing-9) !important;
+}
+.pb-9 {
+ padding-bottom: var(--v2-spacing-9) !important;
+}
diff --git a/src/core/client/ui/components/v2/Box/Box.mdx b/src/core/client/ui/components/v2/Box/Box.mdx
new file mode 100644
index 000000000..e7b8aa2a0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Box/Box.mdx
@@ -0,0 +1,30 @@
+---
+menu: UI Kit
+name: Box
+---
+
+import { Playground } from "docz";
+import Box from "./Box";
+
+# Box
+
+## Usage
+
+
+ First box
+
+ Second box
+
+
+
+## Short Aliases
+
+
+ First box
+
+ Second box
+
+
+ Cloned div
+
+
diff --git a/src/core/client/ui/components/v2/Box/Box.tsx b/src/core/client/ui/components/v2/Box/Box.tsx
new file mode 100644
index 000000000..4a00ccbd9
--- /dev/null
+++ b/src/core/client/ui/components/v2/Box/Box.tsx
@@ -0,0 +1,164 @@
+import cn from "classnames";
+import React, {
+ FunctionComponent,
+ HTMLAttributes,
+ ReactElement,
+ Ref,
+} from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Spacing } from "coral-ui/theme/variables";
+
+import styles from "./Box.css";
+
+interface Props extends HTMLAttributes {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+
+ /* Margin */
+ m?: Spacing;
+ mx?: Spacing;
+ my?: Spacing;
+ margin?: Spacing;
+ marginStart?: Spacing;
+ marginEnd?: Spacing;
+ marginLeft?: Spacing;
+ marginRight?: Spacing;
+ marginTop?: Spacing;
+ marginBottom?: Spacing;
+ ms?: Spacing;
+ me?: Spacing;
+ ml?: Spacing;
+ mr?: Spacing;
+ mt?: Spacing;
+ mb?: Spacing;
+
+ /* Padding */
+ p?: Spacing;
+ px?: Spacing;
+ py?: Spacing;
+ padding?: Spacing;
+ paddingStart?: Spacing;
+ paddingEnd?: Spacing;
+ paddingLeft?: Spacing;
+ paddingRight?: Spacing;
+ paddingTop?: Spacing;
+ paddingBottom?: Spacing;
+ ps?: Spacing;
+ pe?: Spacing;
+ pl?: Spacing;
+ pr?: Spacing;
+ pt?: Spacing;
+ pb?: Spacing;
+
+ /** If set, will perform React.cloneElement instead */
+ clone?: boolean;
+
+ /** The name of the Box to render */
+ children?: React.ReactNode;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+
+ /**
+ * The container used for the root node.
+ * Either a string to use a DOM element, a component, or an element.
+ */
+ container?: React.ReactElement | React.ComponentType | string;
+}
+
+const Box: FunctionComponent = props => {
+ const {
+ clone,
+ classes,
+ className,
+ forwardRef,
+ container,
+ children,
+ m,
+ mx,
+ my,
+ margin,
+ marginStart,
+ marginEnd,
+ marginLeft,
+ marginRight,
+ marginTop,
+ marginBottom,
+ ml,
+ mr,
+ ms,
+ me,
+ mt,
+ mb,
+ p,
+ px,
+ py,
+ padding,
+ paddingStart,
+ paddingEnd,
+ paddingLeft,
+ paddingRight,
+ paddingTop,
+ paddingBottom,
+ pl,
+ pr,
+ ps,
+ pe,
+ pt,
+ pb,
+ ...rest
+ } = props;
+ const final = {
+ ml: ml || marginLeft || ms || marginStart || mx || m || margin,
+ mr: mr || marginRight || me || marginEnd || mx || m || margin,
+ mt: mt || marginTop || my || m || margin,
+ mb: mb || marginBottom || my || m || margin,
+ pl: pl || paddingLeft || ps || paddingStart || px || p || padding,
+ pr: pr || paddingRight || pe || paddingEnd || px || p || padding,
+ pt: pt || paddingTop || py || p || padding,
+ pb: pb || paddingBottom || py || p || padding,
+ };
+ const rootClassName = cn(
+ classes.root,
+ className,
+ /* Margin */
+ final.ml && (classes as any)[`ml-${final.ml}`],
+ final.mr && (classes as any)[`mr-${final.mr}`],
+ final.mt && (classes as any)[`mt-${final.mt}`],
+ final.mb && (classes as any)[`mb-${final.mb}`],
+ /* Padding */
+ final.pl && (classes as any)[`pl-${final.pl}`],
+ final.pr && (classes as any)[`pr-${final.pr}`],
+ final.pt && (classes as any)[`pt-${final.pt}`],
+ final.pb && (classes as any)[`pb-${final.pb}`]
+ );
+
+ const innerProps = {
+ className: rootClassName,
+ ref: forwardRef,
+ ...rest,
+ };
+
+ const Container = container!;
+
+ if (clone) {
+ const child = React.Children.only(children) as ReactElement;
+ return React.cloneElement(child, innerProps);
+ }
+ if (React.isValidElement(Container)) {
+ return React.cloneElement(Container, { ...innerProps, children });
+ } else {
+ return {children} ;
+ }
+};
+
+Box.defaultProps = {
+ container: "div",
+} as Partial;
+
+const enhanced = withForwardRef(withStyles(styles)(Box));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Box/index.ts b/src/core/client/ui/components/v2/Box/index.ts
new file mode 100644
index 000000000..772ab37c1
--- /dev/null
+++ b/src/core/client/ui/components/v2/Box/index.ts
@@ -0,0 +1 @@
+export { default } from "./Box";
diff --git a/src/core/client/ui/components/v2/Button/Button.css b/src/core/client/ui/components/v2/Button/Button.css
new file mode 100644
index 000000000..59b7bcc48
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/Button.css
@@ -0,0 +1,508 @@
+/* Design tokens */
+
+$button-default-outline-background: var(--v2-colors-pure-white);
+$button-default-outline-foreground: var(--v2-colors-teal-600);
+$button-default-outline-active: var(--v2-colors-teal-500);
+
+$button-default-filled-background: var(--v2-colors-teal-600);
+$button-default-filled-foreground: var(--v2-colors-pure-white);
+$button-default-filled-hover: var(--v2-colors-teal-500);
+$button-default-filled-active: var(--v2-colors-teal-400);
+
+$button-alert-outline-background: var(--v2-colors-pure-white);
+$button-alert-outline-foreground: var(--v2-colors-red-500);
+$button-alert-outline-active: var(--v2-colors-red-400);
+
+$button-alert-filled-background: var(--v2-colors-red-500);
+$button-alert-filled-foreground: var(--v2-colors-pure-white);
+$button-alert-filled-hover: var(--v2-colors-red-400);
+$button-alert-filled-active: var(--v2-colors-red-300);
+
+$button-emphasis-outline-background: var(--v2-colors-pure-white);
+$button-emphasis-outline-foreground: var(--v2-colors-blue-500);
+$button-emphasis-outline-active: var(--v2-colors-blue-400);
+
+$button-emphasis-filled-background: var(--v2-colors-blue-500);
+$button-emphasis-filled-foreground: var(--v2-colors-pure-white);
+$button-emphasis-filled-hover: var(--v2-colors-blue-400);
+$button-emphasis-filled-active: var(--v2-colors-blue-300);
+
+$button-mono-outline-background: var(--v2-colors-pure-white);
+$button-mono-outline-foreground: var(--v2-colors-grey-600);
+$button-mono-outline-active: var(--v2-colors-grey-500);
+
+$button-mono-filled-background: var(--v2-colors-grey-600);
+$button-mono-filled-foreground: var(--v2-colors-pure-white);
+$button-mono-filled-hover: var(--v2-colors-grey-500);
+$button-mono-filled-active: var(--v2-colors-grey-400);
+
+$button-adornment-foreground: var(--v2-colors-pure-white);
+
+$button-adornment-default-background: var(--v2-colors-teal-600);
+$button-adornment-alert-background: var(--v2-colors-red-500);
+$button-adornment-emphasis-background: var(--v2-colors-blue-500);
+$button-adornment-mono-background: var(--v2-colors-grey-600);
+
+$button-adornment-default-hover: var(--v2-colors-teal-500);
+$button-adornment-alert-hover: var(--v2-colors-red-400);
+$button-adornment-emphasis-hover: var(--v2-colors-blue-400);
+$button-adornment-mono-hover: var(--v2-colors-grey-400);
+
+$button-adornment-default-active: var(--v2-colors-teal-400);
+$button-adornment-alert-active: var(--v2-colors-red-300);
+$button-adornment-emphasis-active: var(--v2-colors-blue-300);
+$button-adornment-mono-active: var(--v2-colors-grey-300);
+
+$button-ghost-default-foreground: var(--v2-colors-teal-600);
+$button-ghost-alert-foreground: var(--v2-colors-red-500);
+$button-ghost-emphasis-foreground: var(--v2-colors-blue-500);
+$button-ghost-mono-foreground: var(--v2-colors-grey-600);
+
+$button-ghost-active-foreground: var(--v2-colors-pure-white);
+
+$button-underlined-default-foreground: var(--v2-colors-teal-600);
+$button-underlined-alert-foreground: var(--v2-colors-red-500);
+$button-underlined-emphasis-foreground: var(--v2-colors-blue-500);
+$button-underlined-mono-foreground: var(--v2-colors-grey-600);
+
+$button-underlined-default-hover: var(--v2-colors-teal-500);
+$button-underlined-alert-hover: var(--v2-colors-red-400);
+$button-underlined-emphasis-hover: var(--v2-colors-blue-400);
+$button-underlined-mono-hover: var(--v2-colors-grey-500);
+
+$button-underlined-default-active: var(--v2-colors-teal-400);
+$button-underlined-alert-active: var(--v2-colors-red-300);
+$button-underlined-emphasis-active: var(--v2-colors-blue-300);
+$button-underlined-mono-active: var(--v2-colors-grey-400);
+
+/* Class Definitions */
+
+.root {
+ border-radius: var(--v2-round-corners);
+ background-color: transparent;
+ position: relative;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ box-sizing: border-box;
+ border: 0px solid transparent;
+
+ & > * {
+ margin: 0 var(--v2-spacing-1) 0 0;
+ /* convince safari */
+ align-self: center;
+ }
+ & > *:last-child {
+ margin: 0;
+ }
+}
+
+.uppercase {
+ text-transform: uppercase;
+}
+
+.root.disabled {
+ opacity: 0.4;
+ cursor: default;
+}
+
+.fullWidth {
+ display: flex;
+ width: 100%;
+ box-sizing: border-box;
+}
+
+.sizeSmall {
+ color: $button-default-outline-foreground;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: 1;
+
+ padding: var(--v2-spacing-1);
+}
+
+.sizeMedium {
+ color: $button-default-outline-foreground;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: 1.28;
+
+ padding: var(--v2-spacing-3) var(--v2-spacing-5);
+}
+
+.sizeLarge {
+ color: $button-default-outline-foreground;
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-line-height-reset);
+ line-height: 1.25;
+
+ padding: var(--v2-spacing-4) var(--v2-spacing-6);
+}
+
+.variantDefault,
+.variantPlain {
+ &.colorDefault {
+ color: $button-default-outline-foreground;
+ }
+ &.colorAlert {
+ color: $button-alert-outline-foreground;
+ }
+ &.colorEmphasis {
+ color: $button-emphasis-outline-foreground;
+ }
+ &.colorMono {
+ color: $button-mono-outline-foreground;
+ }
+}
+
+.variantDefault {
+ border-width: 1px;
+ &.colorDefault {
+ border-color: $button-default-outline-foreground;
+ background-color: $button-default-outline-background;
+ }
+ &.colorAlert {
+ border-color: $button-alert-outline-foreground;
+ background-color: $button-alert-outline-background;
+ }
+ &.colorEmphasis {
+ border-color: $button-emphasis-outline-foreground;
+ background-color: $button-emphasis-outline-background;
+ }
+ &.colorMono {
+ border-color: $button-mono-outline-foreground;
+ background-color: $button-mono-outline-background;
+ }
+
+ &:not(.disabled) {
+ &.colorDefault {
+ &.mouseHover {
+ background-color: $button-default-outline-foreground;
+ color: $button-default-outline-background;
+ }
+ &:active,
+ &.active {
+ color: $button-default-outline-background;
+ border-color: $button-default-outline-active;
+ background-color: $button-default-outline-active;
+ }
+ }
+ &.colorAlert {
+ &.mouseHover {
+ color: $button-alert-outline-background;
+ background-color: $button-alert-outline-foreground;
+ }
+ &:active,
+ &.active {
+ color: $button-alert-outline-background;
+ border-color: $button-alert-outline-active;
+ background-color: $button-alert-outline-active;
+ }
+ }
+ &.colorEmphasis {
+ &.mouseHover {
+ color: $button-emphasis-outline-background;
+ background-color: $button-emphasis-outline-foreground;
+ }
+ &:active,
+ &.active {
+ border-color: $button-emphasis-outline-active;
+ background-color: $button-emphasis-outline-active;
+ color: $button-emphasis-outline-background;
+ }
+ }
+ &.colorMono {
+ &.mouseHover {
+ background-color: $button-mono-outline-foreground;
+ color: $button-mono-outline-background;
+ }
+ &:active,
+ &.active {
+ border-color: $button-mono-outline-active;
+ background-color: $button-mono-outline-active;
+ color: $button-mono-outline-background;
+ }
+ }
+ }
+}
+
+.variantPlain {
+ padding: 0;
+}
+
+.variantFilled {
+ border-width: 1px;
+
+ &.colorDefault {
+ border-color: $button-default-filled-background;
+ color: $button-default-filled-foreground;
+ background-color: $button-default-filled-background;
+ }
+ &.colorAlert {
+ border-color: $button-alert-filled-background;
+ color: $button-alert-filled-foreground;
+ background-color: $button-alert-filled-background;
+ }
+ &.colorEmphasis {
+ border-color: $button-emphasis-filled-background;
+ color: $button-emphasis-filled-foreground;
+ background-color: $button-emphasis-filled-background;
+ }
+ &.colorMono {
+ border-color: $button-mono-filled-background;
+ color: $button-mono-filled-foreground;
+ background-color: $button-mono-filled-background;
+ }
+
+ &:not(.disabled) {
+ &.colorDefault {
+ &.mouseHover {
+ border-color: $button-default-filled-hover;
+ color: $button-default-filled-foreground;
+ background-color: $button-default-filled-hover;
+ }
+ &:active,
+ &.active {
+ border-color: $button-default-filled-active;
+ color: $button-default-filled-foreground;
+ background-color: $button-default-filled-active;
+ }
+ }
+ &.colorAlert {
+ &.mouseHover {
+ border-color: $button-alert-filled-hover;
+ color: $button-alert-filled-foreground;
+ background-color: $button-alert-filled-hover;
+ }
+ &:active,
+ &.active {
+ border-color: $button-alert-filled-active;
+ color: $button-alert-filled-foreground;
+ background-color: $button-alert-filled-active;
+ }
+ }
+ &.colorEmphasis {
+ &.mouseHover {
+ border-color: $button-emphasis-filled-hover;
+ color: $button-emphasis-filled-foreground;
+ background-color: $button-emphasis-filled-hover;
+ }
+ &:active,
+ &.active {
+ border-color: $button-emphasis-filled-active;
+ color: $button-emphasis-filled-foreground;
+ background-color: $button-emphasis-filled-active;
+ }
+ }
+ &.colorMono {
+ &.mouseHover {
+ border-color: $button-mono-filled-hover;
+ color: $button-mono-filled-foreground;
+ background-color: $button-mono-filled-hover;
+ }
+ &:active,
+ &.active {
+ border-color: $button-mono-filled-active;
+ color: $button-mono-filled-foreground;
+ background-color: $button-mono-filled-active;
+ }
+ }
+ }
+}
+
+.variantAdornment {
+ color: $button-adornment-foreground;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+
+ &.colorDefault {
+ background-color: $button-adornment-default-background;
+ border-color: $button-adornment-default-background;
+ }
+ &.colorAlert {
+ background-color: $button-adornment-alert-background;
+ border-color: $button-adornment-alert-background;
+ }
+ &.colorEmphasis {
+ background-color: $button-adornment-emphasis-background;
+ border-color: $button-adornment-emphasis-background;
+ }
+ &.colorMono {
+ background-color: $button-adornment-mono-background;
+ border-color: $button-adornment-mono-background;
+ }
+
+ &:not(.disabled) {
+ &.colorDefault {
+ &.mouseHover {
+ background-color: $button-adornment-default-hover;
+ border-color: $button-adornment-default-hover;
+ }
+ &:active,
+ &.active {
+ background-color: $button-adornment-default-active;
+ border-color: $button-adornment-default-active;
+ }
+ }
+ &.colorAlert {
+ &.mouseHover {
+ background-color: $button-adornment-alert-hover;
+ border-color: $button-adornment-alert-hover;
+ }
+ &:active,
+ &.active {
+ background-color: $button-adornment-alert-active;
+ border-color: $button-adornment-alert-active;
+ }
+ }
+ &.colorEmphasis {
+ &.mouseHover {
+ background-color: $button-adornment-emphasis-hover;
+ border-color: $button-adornment-emphasis-hover;
+ }
+ &:active,
+ &.active {
+ background-color: $button-adornment-emphasis-active;
+ border-color: $button-adornment-emphasis-active;
+ }
+ }
+ &.colorMono {
+ &.mouseHover {
+ background-color: $button-adornment-mono-hover;
+ border-color: $button-adornment-mono-hover;
+ }
+ &:active,
+ &.active {
+ background-color: $button-adornment-mono-active;
+ border-color: $button-adornment-mono-active;
+ }
+ }
+ }
+}
+
+.variantGhost {
+ border: 1px solid transparent;
+
+ &.colorDefault {
+ color: $button-ghost-default-foreground;
+ }
+ &.colorAlert {
+ color: $button-ghost-alert-foreground;
+ }
+ &.colorEmphasis {
+ color: $button-ghost-emphasis-foreground;
+ }
+ &.colorMono {
+ color: $button-ghost-mono-foreground;
+ }
+
+ &:not(.disabled) {
+ &.colorDefault {
+ &.mouseHover {
+ border: 1px solid currentColor;
+ }
+ &:active,
+ &.active {
+ border: 1px solid currentColor;
+ color: $button-ghost-active-foreground;
+ background-color: $button-ghost-default-foreground;
+ }
+ }
+ &.colorAlert {
+ &.mouseHover {
+ border: 1px solid currentColor;
+ }
+ &:active,
+ &.active {
+ border: 1px solid currentColor;
+ color: $button-ghost-active-foreground;
+ background-color: $button-ghost-alert-foreground;
+ }
+ }
+ &.colorEmphasis {
+ &.mouseHover {
+ border: 1px solid currentColor;
+ }
+ &:active,
+ &.active {
+ border: 1px solid currentColor;
+ color: $button-ghost-active-foreground;
+ background-color: $button-ghost-emphasis-foreground;
+ }
+ }
+ &.colorMono {
+ &.mouseHover {
+ border: 1px solid currentColor;
+ }
+ &:active,
+ &.active {
+ border: 1px solid currentColor;
+ color: $button-ghost-active-foreground;
+ background-color: $button-ghost-mono-foreground;
+ }
+ }
+ }
+}
+
+.variantUnderlined {
+ padding-right: 0px;
+ padding-left: 0px;
+ border-radius: 0;
+ border-bottom: 1px solid currentColor;
+ padding: 0;
+
+ &.colorDefault {
+ color: $button-underlined-default-foreground;
+ }
+ &.colorAlert {
+ color: $button-underlined-alert-foreground;
+ }
+ &.colorEmphasis {
+ color: $button-underlined-emphasis-foreground;
+ }
+ &.colorMono {
+ color: $button-underlined-mono-foreground;
+ }
+
+ &:not(.disabled) {
+ &.colorDefault {
+ &.mouseHover {
+ color: $button-underlined-default-hover;
+ }
+ &:active,
+ &.active {
+ color: $button-underlined-default-active;
+ }
+ }
+ &.colorAlert {
+ &.mouseHover {
+ color: $button-underlined-alert-hover;
+ }
+ &:active,
+ &.active {
+ color: $button-underlined-alert-active;
+ }
+ }
+ &.colorEmphasis {
+ &.mouseHover {
+ color: $button-underlined-emphasis-hover;
+ }
+ &:active,
+ &.active {
+ color: $button-underlined-emphasis-active;
+ }
+ }
+ &.colorMono {
+ &.mouseHover {
+ color: $button-underlined-mono-hover;
+ }
+ &:active,
+ &.active {
+ color: $button-underlined-mono-active;
+ }
+ }
+ }
+}
diff --git a/src/core/client/ui/components/v2/Button/Button.mdx b/src/core/client/ui/components/v2/Button/Button.mdx
new file mode 100644
index 000000000..6abcd8ed0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/Button.mdx
@@ -0,0 +1,206 @@
+---
+name: Button
+menu: UI Kit
+---
+
+import { Playground } from "docz";
+import Button from "./Button";
+import ButtonIcon from "./ButtonIcon";
+import Icon from "../Icon";
+import TextField from "../TextField";
+import Flex from "../Flex";
+
+# Button
+
+## Regular Button
+
+
+
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+ Push Me
+
+ face
+ Push Me
+
+ Push Me
+
+
+
+## Filled Button
+
+
+
+ Push Me
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ face
+ Push Me
+
+
+ Push Me
+
+
+
+
+## Outlined Button
+
+
+
+ Push Me
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ face
+ Push Me
+
+
+ Push Me
+
+
+
+
+## Ghost Button
+
+
+
+ Push Me
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ face
+ Push Me
+
+
+ Push Me
+
+
+
+
+## Underlined Button
+
+
+
+ Push Me
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ Push Me
+
+
+ face
+ Push Me
+
+
+ Push Me
+
+
+
+
+## TextField Adornment
+
+
+
+
+ search
+
+ }
+ />
+
+
diff --git a/src/core/client/ui/components/v2/Button/Button.spec.tsx b/src/core/client/ui/components/v2/Button/Button.spec.tsx
new file mode 100644
index 000000000..608953104
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/Button.spec.tsx
@@ -0,0 +1,62 @@
+import React from "react";
+import ShallowRenderer from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import { Button } from "./Button";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ classes: {
+ mouseHover: "mouseHover",
+ keyboardFocus: "keyboardFocus",
+ } as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("forwards ref", () => {
+ const props: PropTypesOf = {
+ // eslint-disable-next-line:no-empty
+ forwardRef: () => {},
+ classes: {} as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("renders a medium sized, alert colored filled button with fullWidth", () => {
+ const props: PropTypesOf = {
+ color: "alert",
+ variant: "filled",
+ fullWidth: true,
+ classes: {
+ colorAlert: "colorAlert",
+ variantFilled: "variantFilled",
+ sizeMedium: "sizeMedium",
+ fullWidth: "fullWidth",
+ } as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("renders active state", () => {
+ const props: PropTypesOf = {
+ active: true,
+ classes: {
+ active: "active",
+ } as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Button/Button.tsx b/src/core/client/ui/components/v2/Button/Button.tsx
new file mode 100644
index 000000000..dd0a4c2cd
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/Button.tsx
@@ -0,0 +1,118 @@
+import cn from "classnames";
+import { pick } from "lodash";
+import React, { Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Omit, PropTypesOf } from "coral-ui/types";
+
+import BaseButton, { BaseButtonProps } from "../BaseButton";
+
+import styles from "./Button.css";
+
+interface Props extends Omit {
+ /** If set renders an anchor tag instead */
+ anchor?: boolean;
+ href?: string;
+ target?: string;
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles & BaseButtonProps["classes"];
+
+ /** Size of the button */
+ size?: "small" | "medium" | "large";
+
+ /** Color of the button */
+ color?: "default" | "alert" | "emphasis" | "mono";
+
+ /** Variant of the button */
+ variant?:
+ | "default"
+ | "filled"
+ | "adornment"
+ | "ghost"
+ | "underlined"
+ | "plain";
+
+ /** If set renders a full width button */
+ fullWidth?: boolean;
+
+ /** if set to false, button text will not be uppercase */
+ uppercase?: boolean;
+
+ /** If set renders active state e.g. to implement toggle buttons */
+ active?: boolean;
+
+ type?: "submit" | "reset" | "button";
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+export class Button extends React.Component {
+ public static defaultProps: Partial = {
+ size: "medium",
+ variant: "default",
+ color: "default",
+ uppercase: true,
+ };
+ public render() {
+ const {
+ active,
+ classes,
+ color,
+ className,
+ size,
+ fullWidth,
+ disabled,
+ forwardRef,
+ variant,
+ type,
+ uppercase,
+ ...rest
+ } = this.props;
+
+ const rootClassName = cn(
+ classes.root,
+ {
+ [classes.sizeMedium]: size === "medium",
+ [classes.sizeSmall]: size === "small",
+ [classes.sizeLarge]: size === "large",
+ [classes.colorDefault]: color === "default",
+ [classes.colorAlert]: color === "alert",
+ [classes.colorEmphasis]: color === "emphasis",
+ [classes.colorMono]: color === "mono",
+ [classes.variantDefault]: variant === "default",
+ [classes.variantFilled]: variant === "filled",
+ [classes.variantAdornment]: variant === "adornment",
+ [classes.variantGhost]: variant === "ghost",
+ [classes.variantUnderlined]: variant === "underlined",
+ [classes.variantPlain]: variant === "plain",
+ [classes.uppercase]: uppercase,
+ [classes.fullWidth]: fullWidth,
+ [classes.active]: active,
+ [classes.disabled]: disabled,
+ },
+ className
+ );
+
+ return (
+
+ );
+ }
+}
+
+const enhanced = withForwardRef(withStyles(styles)(Button));
+export type ButtonProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Button/ButtonIcon.css b/src/core/client/ui/components/v2/Button/ButtonIcon.css
new file mode 100644
index 000000000..424b6db73
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/ButtonIcon.css
@@ -0,0 +1,8 @@
+.root {
+ &:first-child {
+ margin-left: -4px;
+ }
+ &:last-child {
+ margin-right: -4px;
+ }
+}
diff --git a/src/core/client/ui/components/v2/Button/ButtonIcon.spec.tsx b/src/core/client/ui/components/v2/Button/ButtonIcon.spec.tsx
new file mode 100644
index 000000000..4f82cb0bc
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/ButtonIcon.spec.tsx
@@ -0,0 +1,30 @@
+import React from "react";
+import ShallowRenderer from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import { ButtonIcon } from "./ButtonIcon";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ classes: {
+ root: "root",
+ } as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("forwards ref", () => {
+ const props: PropTypesOf = {
+ // eslint-disable-next-line:no-empty
+ forwardRef: () => {},
+ classes: {} as any,
+ children: "Push me",
+ };
+ const renderer = ShallowRenderer.createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Button/ButtonIcon.tsx b/src/core/client/ui/components/v2/Button/ButtonIcon.tsx
new file mode 100644
index 000000000..e7b566be0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/ButtonIcon.tsx
@@ -0,0 +1,38 @@
+import cn from "classnames";
+import React, { FunctionComponent, HTMLAttributes, Ref } from "react";
+
+import Icon, { IconProps } from "coral-ui/components/v2/Icon";
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Omit, PropTypesOf } from "coral-ui/types";
+
+import styles from "./ButtonIcon.css";
+
+interface Props extends Omit, "color"> {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles & IconProps["classes"];
+
+ size?: IconProps["size"];
+
+ /** The name of the icon to render */
+ children: string;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+export const ButtonIcon: FunctionComponent = props => {
+ const { classes, className, forwardRef, ...rest } = props;
+ const rootClassName = cn(classes.root, className);
+ return ;
+};
+
+ButtonIcon.defaultProps = {
+ size: "sm",
+} as Partial;
+
+const enhanced = withForwardRef(withStyles(styles)(ButtonIcon));
+export type ButtonIconProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Button/__snapshots__/Button.spec.tsx.snap b/src/core/client/ui/components/v2/Button/__snapshots__/Button.spec.tsx.snap
new file mode 100644
index 000000000..b6e2d69c0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/__snapshots__/Button.spec.tsx.snap
@@ -0,0 +1,51 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`forwards ref 1`] = `
+
+ Push me
+
+`;
+
+exports[`renders a medium sized, alert colored filled button with fullWidth 1`] = `
+
+ Push me
+
+`;
+
+exports[`renders active state 1`] = `
+
+ Push me
+
+`;
+
+exports[`renders correctly 1`] = `
+
+ Push me
+
+`;
diff --git a/src/core/client/ui/components/v2/Button/__snapshots__/ButtonIcon.spec.tsx.snap b/src/core/client/ui/components/v2/Button/__snapshots__/ButtonIcon.spec.tsx.snap
new file mode 100644
index 000000000..f22026d07
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/__snapshots__/ButtonIcon.spec.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`forwards ref 1`] = `
+
+ Push me
+
+`;
+
+exports[`renders correctly 1`] = `
+
+ Push me
+
+`;
diff --git a/src/core/client/ui/components/v2/Button/index.ts b/src/core/client/ui/components/v2/Button/index.ts
new file mode 100644
index 000000000..e17fab004
--- /dev/null
+++ b/src/core/client/ui/components/v2/Button/index.ts
@@ -0,0 +1,2 @@
+export { default, default as Button, ButtonProps } from "./Button";
+export { default as ButtonIcon, ButtonIconProps } from "./ButtonIcon";
diff --git a/src/core/client/ui/components/v2/CallOut/CallOut.css b/src/core/client/ui/components/v2/CallOut/CallOut.css
new file mode 100644
index 000000000..62db447a5
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/CallOut.css
@@ -0,0 +1,51 @@
+$callout-regular-bg: var(--v2-colors-grey-100);
+$callout-regular-text: var(--v2-colors-mono-500);
+$callout-regular-border: var(--v2-colors-grey-300);
+
+.root {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ position: relative;
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ padding: var(--v2-spacing-4);
+ box-sizing: border-box;
+ border-width: 1px;
+ border-style: solid;
+ word-break: break-word;
+}
+
+.borderless {
+ border-style: none;
+}
+
+.colorRegular {
+ background-color: $callout-regular-bg;
+ border-color: $callout-regular-border;
+ color: $callout-regular-text;
+}
+
+.colorPrimary {
+ background-color: var(--palette-primary-lightest);
+ border-color: var(--palette-primary-light);
+ color: var(--palette-text-primary);
+}
+
+.colorError {
+ background-color: var(--palette-error-lightest);
+ border-color: var(--palette-error-light);
+ color: var(--palette-text-primary);
+}
+
+.colorSuccess {
+ background-color: var(--palette-success-lightest);
+ border-color: var(--palette-success-light);
+ color: var(--palette-text-primary);
+}
+
+.fullWidth {
+ display: flex;
+ width: 100%;
+}
diff --git a/src/core/client/ui/components/v2/CallOut/CallOut.mdx b/src/core/client/ui/components/v2/CallOut/CallOut.mdx
new file mode 100644
index 000000000..fb71ea7ee
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/CallOut.mdx
@@ -0,0 +1,23 @@
+---
+name: CallOut
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import CallOut from './CallOut'
+import HorizontalGutter from '../HorizontalGutter'
+
+# CallOut
+
+## Basic Use
+
+
+ This is a component for a callout. Any text that you are wanting to draw attention to such as community guidelines, announcements, etc. can be placed in something like a callout box. The color of the callout box can be customized according your own needs.
+ This is a component for a callout. Any text that you are wanting to draw attention to such as community guidelines, announcements, etc. can be placed in something like a callout box. The color of the callout box can be customized according your own needs.
+ This is a component for a callout. Any text that you are wanting to draw attention to such as community guidelines, announcements, etc. can be placed in something like a callout box. The color of the callout box can be customized according your own needs.
+ The email address or password you entered is incorrect. Try again
+ The email address or password you entered is incorrect. Try again
+
+
+
+
diff --git a/src/core/client/ui/components/v2/CallOut/CallOut.spec.tsx b/src/core/client/ui/components/v2/CallOut/CallOut.spec.tsx
new file mode 100644
index 000000000..e958b1d76
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/CallOut.spec.tsx
@@ -0,0 +1,16 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import CallOut from "./CallOut";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ color: "error",
+ children: "Hello World",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/CallOut/CallOut.tsx b/src/core/client/ui/components/v2/CallOut/CallOut.tsx
new file mode 100644
index 000000000..418dccf19
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/CallOut.tsx
@@ -0,0 +1,73 @@
+import cn from "classnames";
+import React, { FunctionComponent, ReactNode } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./CallOut.css";
+
+export interface CallOutProps {
+ /**
+ * The content of the component.
+ */
+ children: ReactNode;
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /**
+ * Color of the CallOut
+ */
+ color?: "regular" | "primary" | "error" | "success";
+ /*
+ * If set renders a full width CallOut
+ */
+ fullWidth?: boolean;
+
+ /*
+ * If set removes border
+ */
+ borderless?: boolean;
+}
+
+const CallOut: FunctionComponent = props => {
+ const {
+ borderless,
+ className,
+ classes,
+ color,
+ fullWidth,
+ children,
+ ...rest
+ } = props;
+
+ const rootClassName = cn(
+ classes.root,
+ {
+ [classes.colorRegular]: color === "regular",
+ [classes.colorError]: color === "error",
+ [classes.colorPrimary]: color === "primary",
+ [classes.colorSuccess]: color === "success",
+ [classes.borderless]: borderless,
+ [classes.fullWidth]: fullWidth,
+ },
+ className
+ );
+
+ return (
+
+ );
+};
+
+CallOut.defaultProps = {
+ color: "regular",
+ fullWidth: false,
+} as Partial;
+
+const enhanced = withStyles(styles)(CallOut);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/CallOut/__snapshots__/CallOut.spec.tsx.snap b/src/core/client/ui/components/v2/CallOut/__snapshots__/CallOut.spec.tsx.snap
new file mode 100644
index 000000000..9e568c05b
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/__snapshots__/CallOut.spec.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/CallOut/index.ts b/src/core/client/ui/components/v2/CallOut/index.ts
new file mode 100644
index 000000000..189466420
--- /dev/null
+++ b/src/core/client/ui/components/v2/CallOut/index.ts
@@ -0,0 +1 @@
+export { default } from "./CallOut";
diff --git a/src/core/client/ui/components/v2/Card/Card.css b/src/core/client/ui/components/v2/Card/Card.css
new file mode 100644
index 000000000..c19d02bed
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/Card.css
@@ -0,0 +1,18 @@
+.root {
+ position: relative;
+ padding: var(--v2-spacing-4);
+ box-sizing: border-box;
+ border: 1px solid rgba(0, 0, 0, 0.25);
+ box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.25);
+ border-radius: var(--round-corners);
+ background-color: var(--palette-common-white);
+ /*
+ Fallback begin
+
+ Unfortunately Firefox / IE does not support
+ `word-break: break-word` yet.
+ */
+ word-break: break-all;
+ /* Fallback end */
+ word-break: break-word;
+}
diff --git a/src/core/client/ui/components/v2/Card/Card.mdx b/src/core/client/ui/components/v2/Card/Card.mdx
new file mode 100644
index 000000000..8de7390ce
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/Card.mdx
@@ -0,0 +1,37 @@
+---
+name: Card
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+
+import Card from "./Card";
+import CloseButton from "./CloseButton";
+import HorizontalGutter from "../HorizontalGutter";
+
+# Card
+
+## Basic Use
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+ commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+ velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
+ est laborum.
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+ incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
+ nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+ Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
+ eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
+ in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
diff --git a/src/core/client/ui/components/v2/Card/Card.spec.tsx b/src/core/client/ui/components/v2/Card/Card.spec.tsx
new file mode 100644
index 000000000..030ab9675
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/Card.spec.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Card from "./Card";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ children: "Hello World",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Card/Card.tsx b/src/core/client/ui/components/v2/Card/Card.tsx
new file mode 100644
index 000000000..bba4b3c59
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/Card.tsx
@@ -0,0 +1,39 @@
+import cn from "classnames";
+import React, { FunctionComponent, ReactNode, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+
+import styles from "./Card.css";
+
+export interface CardProps extends React.HTMLAttributes {
+ /**
+ * The content of the component.
+ */
+ children: ReactNode;
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+
+ tabIndex?: number;
+ forwardRef?: Ref;
+}
+
+const Card: FunctionComponent = props => {
+ const { className, classes, children, forwardRef, ...rest } = props;
+
+ const rootClassName = cn(classes.root, className);
+
+ return (
+
+ {children}
+
+ );
+};
+
+const enhanced = withForwardRef(withStyles(styles)(Card));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Card/CloseButton.css b/src/core/client/ui/components/v2/Card/CloseButton.css
new file mode 100644
index 000000000..01b08185a
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/CloseButton.css
@@ -0,0 +1,8 @@
+.root {
+ min-height: 0px;
+ margin-right: -5px;
+}
+
+.icon {
+ display: block;
+}
diff --git a/src/core/client/ui/components/v2/Card/CloseButton.tsx b/src/core/client/ui/components/v2/Card/CloseButton.tsx
new file mode 100644
index 000000000..4f3247e7c
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/CloseButton.tsx
@@ -0,0 +1,41 @@
+import React, { FunctionComponent, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Omit, PropTypesOf } from "coral-ui/types";
+
+import BaseButton from "../BaseButton";
+import Flex from "../Flex";
+import Icon from "../Icon";
+
+import styles from "./CloseButton.css";
+
+export interface CloseButtonProps
+ extends Omit, "ref"> {
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles & PropTypesOf["classes"];
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const CloseButton: FunctionComponent = props => {
+ const {
+ classes: { icon: iconClassName, ...restClasses },
+ forwardRef,
+ ...rest
+ } = props;
+ return (
+
+
+
+ close
+
+
+
+ );
+};
+
+const enhanced = withForwardRef(withStyles(styles)(CloseButton));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Card/__snapshots__/Card.spec.tsx.snap b/src/core/client/ui/components/v2/Card/__snapshots__/Card.spec.tsx.snap
new file mode 100644
index 000000000..ab86ffe73
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/__snapshots__/Card.spec.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ Hello World
+
+`;
diff --git a/src/core/client/ui/components/v2/Card/index.ts b/src/core/client/ui/components/v2/Card/index.ts
new file mode 100644
index 000000000..68d2a3f46
--- /dev/null
+++ b/src/core/client/ui/components/v2/Card/index.ts
@@ -0,0 +1,2 @@
+export { default } from "./Card";
+export { default as CardCloseButton } from "./CloseButton";
diff --git a/src/core/client/ui/components/v2/CheckBox/CheckBox.css b/src/core/client/ui/components/v2/CheckBox/CheckBox.css
new file mode 100644
index 000000000..6c4a6f340
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/CheckBox.css
@@ -0,0 +1,91 @@
+.root {
+}
+
+.input {
+ cursor: pointer;
+ position: absolute; /* take it out of document flow */
+ opacity: 0; /* hide it */
+}
+
+.label {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+ user-select: none;
+ padding-left: calc(var(--v2-spacing-3) + 14px);
+ color: var(--v2-palette-input-label);
+ font-size: var(--v2-font-size-3);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+}
+
+.labelSpan {
+ padding-bottom: 1px;
+}
+
+.labelLight {
+ color: var(--palette-text-light);
+}
+
+/* Box. */
+.input + .label:before {
+ content: "";
+ position: absolute;
+ left: 0px;
+ top: 50%;
+ transform: translateY(-50%);
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ background: var(--v2-palette-input-background);
+ border: 1px solid var(--v2-palette-input-label);
+ box-sizing: border-box;
+}
+
+/* Box focus */
+.label.focus:before {
+ @mixin outline;
+}
+
+/* Box checked */
+.input:checked + .label:before {
+ background: var(--v2-palette-primary-main);
+ border: 1px solid var(--v2-palette-primary-main);
+}
+
+/* Disabled state label. */
+.input:disabled + .label {
+ cursor: auto;
+ opacity: 0.6;
+}
+
+/* Disabled box. */
+.input:disabled + .label:before {
+ box-shadow: none;
+ border: 1px solid var(--v2-palette-input-disabled-foreground);
+ background: var(--v2-palette-input-disabled-background);
+}
+
+/* Checkmark. Could be replaced with an image */
+.input:checked + .label:after {
+ content: "";
+ position: absolute;
+ left: 2px;
+ top: 50%;
+ margin-top: -1px;
+ transform: translateY(-50%);
+ color: var(--v2-palette-input-background);
+ background: currentColor;
+ width: 2px;
+ height: 2px;
+ box-shadow: 2px 0 0 currentColor, 4px 0 0 currentColor,
+ 4px -2px 0 currentColor, 4px -4px 0 currentColor, 4px -6px 0 currentColor,
+ 4px -8px 0 currentColor;
+ transform: rotate(45deg);
+ box-sizing: border-box;
+}
+
+.input:checked:disabled + .label:after {
+ color: var(--v2-palette-input-disabled-foreground);
+}
diff --git a/src/core/client/ui/components/v2/CheckBox/CheckBox.mdx b/src/core/client/ui/components/v2/CheckBox/CheckBox.mdx
new file mode 100644
index 000000000..ae33bbbf5
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/CheckBox.mdx
@@ -0,0 +1,19 @@
+---
+name: CheckBox
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import CheckBox from './CheckBox.tsx'
+import HorizontalGutter from '../HorizontalGutter'
+
+# CheckBox
+
+## Basic Use
+
+
+ Yes I agree
+ No I don't agree
+ I don't know
+
+
diff --git a/src/core/client/ui/components/v2/CheckBox/CheckBox.spec.tsx b/src/core/client/ui/components/v2/CheckBox/CheckBox.spec.tsx
new file mode 100644
index 000000000..00c6a5562
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/CheckBox.spec.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import CheckBox from "./CheckBox";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ id: "checkboxID",
+ checked: true,
+ children: "Yes I agree",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/CheckBox/CheckBox.tsx b/src/core/client/ui/components/v2/CheckBox/CheckBox.tsx
new file mode 100644
index 000000000..d97a7b102
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/CheckBox.tsx
@@ -0,0 +1,90 @@
+import cn from "classnames";
+import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react";
+import uuid from "uuid/v4";
+
+import { withKeyboardFocus, withStyles } from "coral-ui/hocs";
+
+import styles from "./CheckBox.css";
+
+export interface CheckBoxProps {
+ id?: string;
+ /**
+ * checked or not.
+ */
+ checked?: boolean;
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /**
+ * Mark as readonly
+ */
+ readOnly?: boolean;
+ /**
+ * Name
+ */
+ name?: string;
+ /**
+ * onChange
+ */
+ onChange?: EventHandler>;
+
+ disabled?: boolean;
+ children: React.ReactNode;
+ /**
+ * Display a light text.
+ */
+ light?: boolean;
+
+ // These handlers are passed down by the `withKeyboardFocus` HOC.
+ onFocus: EventHandler>;
+ onBlur: EventHandler>;
+ keyboardFocus: boolean;
+}
+
+class CheckBox extends Component {
+ public state = {
+ randomID: uuid(),
+ };
+ public render() {
+ const {
+ className,
+ classes,
+ id,
+ light,
+ children,
+ keyboardFocus,
+ ...rest
+ } = this.props;
+
+ const rootClassName = cn(classes.root, className);
+ const finalID = id || this.state.randomID;
+
+ return (
+
+
+
+ {children}
+
+
+ );
+ }
+}
+
+const enhanced = withStyles(styles)(withKeyboardFocus(CheckBox));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/CheckBox/__snapshots__/CheckBox.spec.tsx.snap b/src/core/client/ui/components/v2/CheckBox/__snapshots__/CheckBox.spec.tsx.snap
new file mode 100644
index 000000000..11ce87d61
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/__snapshots__/CheckBox.spec.tsx.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+
+
+
+ Yes I agree
+
+
+
+`;
diff --git a/src/core/client/ui/components/v2/CheckBox/index.ts b/src/core/client/ui/components/v2/CheckBox/index.ts
new file mode 100644
index 000000000..151b40bd5
--- /dev/null
+++ b/src/core/client/ui/components/v2/CheckBox/index.ts
@@ -0,0 +1,2 @@
+export * from "./CheckBox";
+export { default } from "./CheckBox";
diff --git a/src/core/client/ui/components/v2/ClickOutside/ClickOutside.mdx b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.mdx
new file mode 100644
index 000000000..04bd19da7
--- /dev/null
+++ b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.mdx
@@ -0,0 +1,30 @@
+---
+name: ClickOutside
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import ClickOutside from './ClickOutside'
+import Button from '../Button/Button'
+
+# ClickOutside
+
+A Component to handle click events outside the children components.
+
+## Basic usage
+Wrap a Component with `` and pass a function to `onClickOutside`. This function will trigger when the user
+clicks outside the component.
+
+### Test
+Click the blue background. It should trigger an alert. Nothing should happen if you click the button.
+
+
+
+ {
+ if (e.srcElement.id === "outside") {
+ alert('You clicked outside!');
+ }}}>
+ Push Me
+
+
+
diff --git a/src/core/client/ui/components/v2/ClickOutside/ClickOutside.spec.tsx b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.spec.tsx
new file mode 100644
index 000000000..e70821644
--- /dev/null
+++ b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.spec.tsx
@@ -0,0 +1,122 @@
+import { mount } from "enzyme";
+import React from "react";
+import simulant from "simulant";
+import sinon from "sinon";
+
+import UIContext from "../UIContext";
+import {
+ ClickFarAwayCallback,
+ ClickFarAwayRegister,
+ ClickOutside,
+ default as ClickOutsideWithContext,
+} from "./ClickOutside";
+
+let container: HTMLElement;
+
+beforeAll(() => {
+ container = document.createElement("div");
+ document.body.appendChild(container);
+});
+
+afterAll(() => {
+ document.body.removeChild(container);
+});
+
+it("should render correctly", () => {
+ const noop = () => null;
+ const wrapper = mount(
+
+ Hello World!
+
+ );
+ expect(wrapper.html()).toMatchSnapshot();
+ wrapper.unmount();
+});
+
+it("should detect click outside", () => {
+ const onClickOutside = sinon.spy();
+ const wrapper = mount(
+
+ Hello World!
+ ,
+ {
+ attachTo: container,
+ }
+ );
+ simulant.fire(container, "click");
+
+ expect(onClickOutside.calledOnce).toEqual(true);
+ wrapper.unmount();
+});
+
+it("should ignore click inside", () => {
+ const onClickOutside = sinon.spy();
+ const wrapper = mount(
+
+ Push Me
+ ,
+ {
+ attachTo: container,
+ }
+ );
+
+ const target = document.getElementById("click-outside-test-button")!;
+ simulant.fire(target, "click");
+
+ expect(onClickOutside.calledOnce).toEqual(false);
+ wrapper.unmount();
+});
+
+it("should detect click far away", () => {
+ let emitFarAwayClick: ClickFarAwayCallback = Function;
+ const unlisten = sinon.spy();
+ const registerClickFarAway: ClickFarAwayRegister = cb => {
+ emitFarAwayClick = cb;
+ return unlisten;
+ };
+ const onClickOutside = sinon.spy();
+ const wrapper = mount(
+
+ Push Me
+ ,
+ {
+ attachTo: container,
+ }
+ );
+
+ expect(onClickOutside.calledOnce).toEqual(false);
+ emitFarAwayClick();
+ expect(onClickOutside.calledOnce).toEqual(true);
+ expect(unlisten.calledOnce).toEqual(false);
+ wrapper.unmount();
+ expect(unlisten.calledOnce).toEqual(true);
+});
+
+it("should get registerClickFarAway from context", () => {
+ const registerClickFarAway: ClickFarAwayRegister = sinon.spy();
+ const onClickOutside = sinon.spy();
+ const context: any = {
+ registerClickFarAway,
+ };
+ const wrapper = mount(
+
+
+ Push Me
+
+ ,
+ {
+ attachTo: container,
+ }
+ );
+
+ expect(wrapper.find(ClickOutside).prop("registerClickFarAway")).toEqual(
+ registerClickFarAway
+ );
+ wrapper.unmount();
+});
diff --git a/src/core/client/ui/components/v2/ClickOutside/ClickOutside.tsx b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.tsx
new file mode 100644
index 000000000..ffef90688
--- /dev/null
+++ b/src/core/client/ui/components/v2/ClickOutside/ClickOutside.tsx
@@ -0,0 +1,78 @@
+import React, { FunctionComponent } from "react";
+import { findDOMNode } from "react-dom";
+
+import UIContext from "../UIContext";
+
+export type ClickFarAwayCallback = () => void;
+export type ClickFarAwayUnlistenCallback = () => void;
+
+export type ClickFarAwayRegister = (
+ callback: ClickFarAwayCallback
+) => ClickFarAwayUnlistenCallback;
+
+export interface ClickOutsideProps {
+ onClickOutside: (e?: MouseEvent) => void;
+
+ /**
+ * A way to listen for clicks that are e.g. outside of the
+ * current frame for `ClickOutside`
+ */
+ registerClickFarAway?: ClickFarAwayRegister;
+
+ children: React.ReactNode;
+}
+
+export class ClickOutside extends React.Component {
+ public domNode: Element | null = null;
+ private unlisten?: ClickFarAwayUnlistenCallback;
+
+ public handleClick = (e: MouseEvent) => {
+ const { onClickOutside } = this.props;
+ if (!e || !this.domNode!.contains(e.target as HTMLInputElement)) {
+ // eslint-disable-next-line no-unused-expressions
+ onClickOutside && onClickOutside(e);
+ }
+ };
+
+ public handleClickFarAway = () => {
+ const { onClickOutside } = this.props;
+ // eslint-disable-next-line no-unused-expressions
+ onClickOutside && onClickOutside();
+ };
+
+ public componentDidMount() {
+ // TODO: find another solution to `findDOMNode`.
+ // eslint-disable-next-line react/no-find-dom-node
+ this.domNode = findDOMNode(this) as Element;
+ document.addEventListener("click", this.handleClick, true);
+
+ // Listen to far away clicks.
+ if (this.props.registerClickFarAway) {
+ this.unlisten = this.props.registerClickFarAway(this.handleClickFarAway);
+ }
+ }
+
+ public componentWillUnmount() {
+ document.removeEventListener("click", this.handleClick, true);
+
+ // Unlisten to far away clicks.
+ if (this.unlisten) {
+ this.unlisten();
+ this.unlisten = undefined;
+ }
+ }
+
+ public render() {
+ return this.props.children;
+ }
+}
+
+const ClickOutsideWithContext: FunctionComponent = props => (
+
+ {({ registerClickFarAway }) => (
+
+ )}
+
+);
+
+export default ClickOutsideWithContext;
diff --git a/src/core/client/ui/components/v2/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap b/src/core/client/ui/components/v2/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap
new file mode 100644
index 000000000..883a02a51
--- /dev/null
+++ b/src/core/client/ui/components/v2/ClickOutside/__snapshots__/ClickOutside.spec.tsx.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `"Hello World! "`;
diff --git a/src/core/client/ui/components/v2/ClickOutside/index.ts b/src/core/client/ui/components/v2/ClickOutside/index.ts
new file mode 100644
index 000000000..91803ea08
--- /dev/null
+++ b/src/core/client/ui/components/v2/ClickOutside/index.ts
@@ -0,0 +1 @@
+export { default, ClickFarAwayRegister } from "./ClickOutside";
diff --git a/src/core/client/ui/components/v2/Counter/Counter.css b/src/core/client/ui/components/v2/Counter/Counter.css
new file mode 100644
index 000000000..e884f571b
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/Counter.css
@@ -0,0 +1,56 @@
+.root {
+ font-size: var(--v2-font-size-2);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-reset);
+ letter-spacing: calc(0.2em / 14);
+ border-radius: var(--round-corners);
+ padding: 1px 3px 1px 3px;
+ color: inherit;
+}
+
+.sizeSmall {
+ font-size: var(--v2-font-size-1);
+ padding: 2px 3px;
+ line-height: var(--v2-line-height-reset);
+}
+
+.text {
+ color: var(--v2-palette-counter-badge-foreground);
+}
+
+.colorInherit {
+ background-color: currentColor;
+}
+
+.colorPrimary {
+ background-color: var(--palette-primary-main);
+}
+
+.colorGrey {
+ background-color: var(--palette-grey-lightest);
+ box-shadow: inset 0px 0px 0px 1px var(--palette-grey-dark);
+ & .text {
+ color: var(--palette-grey-dark);
+ }
+}
+
+.colorDark {
+ background-color: var(--palette-grey-dark);
+}
+
+.colorError {
+ background-color: var(--palette-error-darkest);
+}
+
+.colorEmphasis {
+ background-color: var(--v2-palette-counter-badge-background-emphasis);
+}
+
+.colorDefault {
+ background-color: var(--v2-palette-counter-badge-background-default);
+}
+
+.colorAlert {
+ background-color: var(--v2-palette-counter-badge-background-alert);
+}
diff --git a/src/core/client/ui/components/v2/Counter/Counter.mdx b/src/core/client/ui/components/v2/Counter/Counter.mdx
new file mode 100644
index 000000000..73e13787c
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/Counter.mdx
@@ -0,0 +1,34 @@
+---
+name: Counter
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+
+import Flex from "../Flex";
+import Counter from "./Counter";
+
+# Counter
+
+## Basic usage
+
+
+
+ Comments 23
+
+
+
+
+
+ 23
+
+ 15
+
+
+ 10
+
+
+ 20
+
+
+
diff --git a/src/core/client/ui/components/v2/Counter/Counter.spec.tsx b/src/core/client/ui/components/v2/Counter/Counter.spec.tsx
new file mode 100644
index 000000000..a1747e753
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/Counter.spec.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import Counter from "./Counter";
+
+it("renders correctly", () => {
+ const renderer = createRenderer();
+ renderer.render(20 );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Counter/Counter.tsx b/src/core/client/ui/components/v2/Counter/Counter.tsx
new file mode 100644
index 000000000..6f4007ecd
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/Counter.tsx
@@ -0,0 +1,65 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Counter.css";
+
+interface Props {
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /**
+ * The color of the component. It supports those theme colors that make sense for this component.
+ */
+ color?:
+ | "inherit"
+ | "dark"
+ | "grey"
+ | "primary"
+ | "error"
+ | "default"
+ | "emphasis"
+ | "alert";
+
+ size?: "sm" | "md";
+}
+
+const Counter: FunctionComponent = ({
+ classes,
+ color,
+ className,
+ children,
+ size,
+ ...rest
+}) => {
+ const rootClassName = cn(
+ classes.root,
+ {
+ [classes.colorPrimary]: color === "primary",
+ [classes.colorDark]: color === "dark",
+ [classes.colorGrey]: color === "grey",
+ [classes.colorInherit]: color === "inherit",
+ [classes.colorError]: color === "error",
+ [classes.colorDefault]: color === "default",
+ [classes.colorEmphasis]: color === "emphasis",
+ [classes.colorAlert]: color === "alert",
+ [classes.sizeSmall]: size === "sm",
+ },
+ className
+ );
+ return (
+
+ {children}
+
+ );
+};
+
+Counter.defaultProps = {
+ color: "inherit",
+};
+
+const enhanced = withStyles(styles)(Counter);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Counter/__snapshots__/Counter.spec.tsx.snap b/src/core/client/ui/components/v2/Counter/__snapshots__/Counter.spec.tsx.snap
new file mode 100644
index 000000000..44fa0f8ea
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/__snapshots__/Counter.spec.tsx.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ 20
+
+`;
diff --git a/src/core/client/ui/components/v2/Counter/index.ts b/src/core/client/ui/components/v2/Counter/index.ts
new file mode 100644
index 000000000..e09713ba4
--- /dev/null
+++ b/src/core/client/ui/components/v2/Counter/index.ts
@@ -0,0 +1 @@
+export { default } from "./Counter";
diff --git a/src/core/client/ui/components/v2/Delay/Delay.mdx b/src/core/client/ui/components/v2/Delay/Delay.mdx
new file mode 100644
index 000000000..9a3375d97
--- /dev/null
+++ b/src/core/client/ui/components/v2/Delay/Delay.mdx
@@ -0,0 +1,22 @@
+---
+name: Delay
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import Delay from "./Delay.tsx";
+import HorizontalGutter from "../HorizontalGutter";
+import Spinner from "../Spinner";
+
+# Delay
+
+## Basic Use
+
+
+
+ Spinner will show up in 3 seconds
+
+
+
+
+
diff --git a/src/core/client/ui/components/v2/Delay/Delay.spec.tsx b/src/core/client/ui/components/v2/Delay/Delay.spec.tsx
new file mode 100644
index 000000000..668882f5d
--- /dev/null
+++ b/src/core/client/ui/components/v2/Delay/Delay.spec.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Delay from "./Delay";
+
+it("renders correctly", () => {
+ jest.useFakeTimers();
+ try {
+ const props: PropTypesOf = {
+ children: "custom",
+ ms: 3000,
+ };
+ const renderer = TestRenderer.create(Hello );
+ expect(renderer.toJSON()).toMatchSnapshot();
+ jest.advanceTimersByTime(3000);
+ expect(renderer.toJSON()).toMatchSnapshot();
+ } finally {
+ jest.useRealTimers();
+ }
+});
diff --git a/src/core/client/ui/components/v2/Delay/Delay.tsx b/src/core/client/ui/components/v2/Delay/Delay.tsx
new file mode 100644
index 000000000..3c90d65dd
--- /dev/null
+++ b/src/core/client/ui/components/v2/Delay/Delay.tsx
@@ -0,0 +1,28 @@
+import React, { FunctionComponent, useEffect, useState } from "react";
+
+interface Props {
+ ms?: number;
+ children: React.ReactNode;
+}
+
+const Delay: FunctionComponent = ({ ms, children }) => {
+ const [render, setRender] = useState(false);
+ useEffect(() => {
+ const timeout = setTimeout(() => {
+ setRender(true);
+ }, ms);
+ return () => {
+ clearTimeout(timeout);
+ };
+ }, [ms]);
+ if (!render) {
+ return null;
+ }
+ return <>{children}>;
+};
+
+Delay.defaultProps = {
+ ms: 500,
+};
+
+export default Delay;
diff --git a/src/core/client/ui/components/v2/Delay/__snapshots__/Delay.spec.tsx.snap b/src/core/client/ui/components/v2/Delay/__snapshots__/Delay.spec.tsx.snap
new file mode 100644
index 000000000..840f2a190
--- /dev/null
+++ b/src/core/client/ui/components/v2/Delay/__snapshots__/Delay.spec.tsx.snap
@@ -0,0 +1,5 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `null`;
+
+exports[`renders correctly 2`] = `"Hello"`;
diff --git a/src/core/client/ui/components/v2/Delay/index.ts b/src/core/client/ui/components/v2/Delay/index.ts
new file mode 100644
index 000000000..a478b6813
--- /dev/null
+++ b/src/core/client/ui/components/v2/Delay/index.ts
@@ -0,0 +1 @@
+export { default } from "./Delay";
diff --git a/src/core/client/ui/components/v2/Divider/Divider.css b/src/core/client/ui/components/v2/Divider/Divider.css
new file mode 100644
index 000000000..8599c35a4
--- /dev/null
+++ b/src/core/client/ui/components/v2/Divider/Divider.css
@@ -0,0 +1,23 @@
+$divider-border-color: var(--v2-colors-grey-300);
+
+.root {
+ border-top: 0;
+ border-bottom: 1px solid $divider-border-color;
+ padding: 0;
+}
+
+.spacing1 {
+ margin: var(--v2-spacing-1) 0;
+}
+
+.spacing2 {
+ margin: var(--v2-spacing-2) 0;
+}
+
+.spacing3 {
+ margin: var(--v2-spacing-3) 0;
+}
+
+.spacing4 {
+ margin: var(--v2-spacing-4) 0;
+}
diff --git a/src/core/client/ui/components/v2/Divider/Divider.tsx b/src/core/client/ui/components/v2/Divider/Divider.tsx
new file mode 100644
index 000000000..7ab35c851
--- /dev/null
+++ b/src/core/client/ui/components/v2/Divider/Divider.tsx
@@ -0,0 +1,23 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import styles from "./Divider.css";
+
+interface Props {
+ spacing?: 1 | 2 | 3 | 4;
+}
+
+const Divider: FunctionComponent = ({ spacing = 3 }) => {
+ return (
+
+ );
+};
+
+export default Divider;
diff --git a/src/core/client/ui/components/v2/Divider/index.ts b/src/core/client/ui/components/v2/Divider/index.ts
new file mode 100644
index 000000000..980204123
--- /dev/null
+++ b/src/core/client/ui/components/v2/Divider/index.ts
@@ -0,0 +1 @@
+export { default } from "./Divider";
diff --git a/src/core/client/ui/components/v2/Dropdown/Button.css b/src/core/client/ui/components/v2/Dropdown/Button.css
new file mode 100644
index 000000000..1be6ccf8f
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Button.css
@@ -0,0 +1,55 @@
+.root {
+ font-size: var(--v2-font-size-3);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: var(--v2-spacing-2);
+ width: 100%;
+ text-align: left;
+ line-height: 1;
+}
+
+.anchor {
+ color: var(--v2-palette-primary-main);
+ text-decoration: underline;
+ &:visited {
+ color: var(--v2-palette-primary-main);
+ }
+}
+
+.root:disabled {
+ opacity: 0.6;
+}
+
+.root:not(:disabled):active {
+ background-color: var(--v2-palette-primary-lightest);
+}
+
+.mouseHover {
+ background-color: var(--v2-palette-primary-lightest);
+}
+
+.iconBefore {
+ display: flex;
+ justify-content: baseline;
+ align-items: center;
+ color: var(--v2-palette-grey-main);
+ margin-right: var(--spacing-2);
+}
+.iconAfter {
+ display: flex;
+ align-items: center;
+ justify-content: baseline;
+ margin-left: var(--spacing-2);
+ text-decoration: unset;
+}
+.iconOpenInNew {
+ padding-top: 1px;
+ color: var(--v2-palette-primary-main);
+}
+
+.blankAdornment {
+ padding-right: var(--v2-spacing-6);
+}
diff --git a/src/core/client/ui/components/v2/Dropdown/Button.spec.tsx b/src/core/client/ui/components/v2/Dropdown/Button.spec.tsx
new file mode 100644
index 000000000..e25560b72
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Button.spec.tsx
@@ -0,0 +1,32 @@
+import { noop } from "lodash";
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import Button from "./Button";
+
+it("renders anchor button", () => {
+ const props: PropTypesOf = {
+ href: "/moderate",
+ children: "link",
+ onClick: noop,
+ className: "custom",
+ target: "_blank",
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("renders button", () => {
+ const props: PropTypesOf = {
+ children: "link",
+ onClick: noop,
+ className: "custom",
+ blankAdornment: true,
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Dropdown/Button.tsx b/src/core/client/ui/components/v2/Dropdown/Button.tsx
new file mode 100644
index 000000000..b3acc8c5a
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Button.tsx
@@ -0,0 +1,78 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { Omit } from "coral-framework/types";
+import { withStyles } from "coral-ui/hocs";
+
+import BaseButton, { BaseButtonProps } from "coral-ui/components/BaseButton";
+import Icon from "coral-ui/components/Icon";
+
+import { Flex } from "coral-ui/components";
+import styles from "./Button.css";
+
+interface Props extends Omit {
+ children: React.ReactNode;
+ icon?: React.ReactNode;
+ href?: string;
+ className?: string;
+ onClick?: React.EventHandler;
+ classes: typeof styles;
+ /**
+ * adornment if set is rendered at the end of the button.
+ */
+ adornment?: React.ReactNode;
+ /**
+ * blankAdornment if true will leave some blank space after the text, so
+ * that it looks nice, if mixed with other buttons which have an external link
+ * icon as adornment.
+ */
+ blankAdornment?: boolean;
+}
+
+const Button: FunctionComponent = ({
+ blankAdornment,
+ className,
+ href,
+ onClick,
+ children,
+ classes,
+ icon,
+ disabled,
+ adornment,
+ ...rest
+}) => {
+ return (
+
+
+ {icon && {icon}
}
+
+ {children}
+
+
+ {adornment && {adornment}
}
+ {!adornment && rest.target === "_blank" && (
+
+ open_in_new
+
+ )}
+
+ );
+};
+
+export default withStyles(styles)(Button);
diff --git a/src/core/client/ui/components/v2/Dropdown/Divider.css b/src/core/client/ui/components/v2/Dropdown/Divider.css
new file mode 100644
index 000000000..64d612447
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Divider.css
@@ -0,0 +1,6 @@
+.root {
+ border: 0;
+ border-bottom: 1px solid var(--v2-palette-dropdown-divider-border);
+ margin: 0;
+ padding: calc(0.5 * var(--mini-unit)) 0 0 0;
+}
diff --git a/src/core/client/ui/components/v2/Dropdown/Divider.spec.tsx b/src/core/client/ui/components/v2/Dropdown/Divider.spec.tsx
new file mode 100644
index 000000000..0489e8451
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Divider.spec.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import Divider from "./Divider";
+
+it("renders correctly", () => {
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Dropdown/Divider.tsx b/src/core/client/ui/components/v2/Dropdown/Divider.tsx
new file mode 100644
index 000000000..ba0fc2c91
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Divider.tsx
@@ -0,0 +1,17 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Divider.css";
+
+interface Props {
+ className?: string;
+ classes: typeof styles;
+}
+
+const Divider: FunctionComponent = ({ className, classes, ...rest }) => (
+
+);
+
+export default withStyles(styles)(Divider);
diff --git a/src/core/client/ui/components/v2/Dropdown/Dropdown.css b/src/core/client/ui/components/v2/Dropdown/Dropdown.css
new file mode 100644
index 000000000..660ced0b0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Dropdown.css
@@ -0,0 +1,3 @@
+.root {
+ padding: calc(0.5 * var(--mini-unit)) 0;
+}
diff --git a/src/core/client/ui/components/v2/Dropdown/Dropdown.mdx b/src/core/client/ui/components/v2/Dropdown/Dropdown.mdx
new file mode 100644
index 000000000..46ac31ceb
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Dropdown.mdx
@@ -0,0 +1,58 @@
+---
+name: Dropdown
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+
+import {
+ Dropdown,
+ Divider as DropdownDivider,
+ Button as DropdownButton,
+} from "./";
+import { Button, ButtonIcon } from "../Button";
+import ClickOutside from "../ClickOutside";
+import Popover from "../Popover";
+
+# Dropdown
+
+## Basic usage
+
+
+
+
diff --git a/src/core/client/ui/components/v2/Dropdown/Dropdown.spec.tsx b/src/core/client/ui/components/v2/Dropdown/Dropdown.spec.tsx
new file mode 100644
index 000000000..2c70af334
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Dropdown.spec.tsx
@@ -0,0 +1,30 @@
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import Button from "./Button";
+import Divider from "./Divider";
+import Dropdown from "./Dropdown";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: (
+ <>
+ Shortcuts
+
+ Report Bug
+
+
+ Sign Out
+ >
+ ),
+ className: "custom",
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Dropdown/Dropdown.tsx b/src/core/client/ui/components/v2/Dropdown/Dropdown.tsx
new file mode 100644
index 000000000..c3da8b50b
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/Dropdown.tsx
@@ -0,0 +1,27 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Dropdown.css";
+
+interface Props {
+ children?: React.ReactNode;
+ className?: string;
+ classes: typeof styles;
+}
+
+const Dropdown: FunctionComponent = ({
+ className,
+ children,
+ classes,
+ ...rest
+}) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default withStyles(styles)(Dropdown);
diff --git a/src/core/client/ui/components/v2/Dropdown/__snapshots__/Button.spec.tsx.snap b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Button.spec.tsx.snap
new file mode 100644
index 000000000..6c34fec47
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Button.spec.tsx.snap
@@ -0,0 +1,44 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders anchor button 1`] = `
+
+ link
+
+`;
+
+exports[`renders button 1`] = `
+
+ link
+
+`;
diff --git a/src/core/client/ui/components/v2/Dropdown/__snapshots__/Divider.spec.tsx.snap b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Divider.spec.tsx.snap
new file mode 100644
index 000000000..722ea5f94
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Divider.spec.tsx.snap
@@ -0,0 +1,11 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/Dropdown/__snapshots__/Dropdown.spec.tsx.snap b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Dropdown.spec.tsx.snap
new file mode 100644
index 000000000..9c171d0f0
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/__snapshots__/Dropdown.spec.tsx.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+
+
+ Shortcuts
+
+
+ Report Bug
+
+
+
+ Sign Out
+
+
+
+`;
diff --git a/src/core/client/ui/components/v2/Dropdown/index.ts b/src/core/client/ui/components/v2/Dropdown/index.ts
new file mode 100644
index 000000000..ff2882546
--- /dev/null
+++ b/src/core/client/ui/components/v2/Dropdown/index.ts
@@ -0,0 +1,3 @@
+export { default as Dropdown } from "./Dropdown";
+export { default as Button } from "./Button";
+export { default as Divider } from "./Divider";
diff --git a/src/core/client/ui/components/v2/DurationField/DurationField.css b/src/core/client/ui/components/v2/DurationField/DurationField.css
new file mode 100644
index 000000000..d88b02a39
--- /dev/null
+++ b/src/core/client/ui/components/v2/DurationField/DurationField.css
@@ -0,0 +1,15 @@
+.value {
+ width: calc(6 * var(--mini-unit));
+}
+
+.select {
+ height: 100%;
+ min-width: calc(17 * var(--mini-unit));
+}
+
+.unit {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: 36px;
+}
diff --git a/src/core/client/ui/components/v2/DurationField/DurationField.spec.tsx b/src/core/client/ui/components/v2/DurationField/DurationField.spec.tsx
new file mode 100644
index 000000000..7cea24a92
--- /dev/null
+++ b/src/core/client/ui/components/v2/DurationField/DurationField.spec.tsx
@@ -0,0 +1,71 @@
+import { noop } from "lodash";
+import React from "react";
+import { createRenderer } from "react-test-renderer/shallow";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import DurationField, { DURATION_UNIT } from "./DurationField";
+
+it("renders correctly with default units", () => {
+ const props: PropTypesOf = {
+ name: "duration",
+ value: "",
+ disabled: false,
+ onChange: noop,
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("renders correctly with specified units", () => {
+ const props: PropTypesOf = {
+ name: "duration",
+ value: "",
+ disabled: false,
+ onChange: noop,
+ units: [DURATION_UNIT.SECONDS, DURATION_UNIT.HOURS],
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("use best matching unit", () => {
+ const props: PropTypesOf = {
+ name: "duration",
+ value: "3600",
+ disabled: false,
+ onChange: noop,
+ units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("use initial unit if 0", () => {
+ const props: PropTypesOf = {
+ name: "duration",
+ value: "0",
+ disabled: false,
+ onChange: noop,
+ units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
+
+it("accepts invalid input", () => {
+ const props: PropTypesOf = {
+ name: "duration",
+ value: "this is so invalid",
+ disabled: false,
+ onChange: noop,
+ units: [DURATION_UNIT.SECONDS, DURATION_UNIT.MINUTES, DURATION_UNIT.HOURS],
+ };
+ const renderer = createRenderer();
+ renderer.render( );
+ expect(renderer.getRenderOutput()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/DurationField/DurationField.tsx b/src/core/client/ui/components/v2/DurationField/DurationField.tsx
new file mode 100644
index 000000000..b6d4419eb
--- /dev/null
+++ b/src/core/client/ui/components/v2/DurationField/DurationField.tsx
@@ -0,0 +1,176 @@
+import { Localized } from "fluent-react/compat";
+import React, {
+ ChangeEvent,
+ FunctionComponent,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from "react";
+
+import { UNIT } from "coral-common/helpers/i18n";
+import { Flex } from "coral-ui/components";
+
+import { Option, SelectField } from "../SelectField";
+import TextField, { TextFieldProps } from "../TextField";
+
+import styles from "./DurationField.css";
+
+/**
+ * DURATION_UNIT are units that can be used in the
+ * DurationField components.
+ */
+export const DURATION_UNIT = UNIT;
+
+const DURATION_UNIT_MAP = {
+ [DURATION_UNIT.SECONDS]: "second",
+ [DURATION_UNIT.MINUTES]: "minute",
+ [DURATION_UNIT.HOURS]: "hour",
+ [DURATION_UNIT.DAYS]: "day",
+ [DURATION_UNIT.WEEKS]: "week",
+};
+
+interface Props extends Pick {
+ value: string;
+ onChange: (v: string) => void;
+ /** Specifiy units to include */
+ units?: ReadonlyArray;
+}
+
+function convertToSeconds(value: string, unit?: UNIT) {
+ const parsed = parseInt(value, 10);
+ return (isNaN(parsed) || !unit ? value : parsed * unit).toString();
+}
+
+function convertFromSeconds(
+ value: string,
+ units: ReadonlyArray,
+ unit?: UNIT
+) {
+ const parsed = parseInt(value, 10);
+
+ // If value was a valid number..
+ if (!isNaN(parsed)) {
+ // If unit is not set, we'll find the best matching unit.
+ if (!unit) {
+ // Start from the first unit,
+ // keep first unit if value is set to 0,
+ // otherwise use better matching unit if the value is fully dividable by the unit.
+ unit = units.reduce((x, cur) =>
+ parsed % cur === 0 && parsed !== 0 ? cur : x
+ );
+ }
+ // Compute new value relative to the selected unit.
+ value = (parsed / unit).toString();
+ }
+
+ return {
+ unit,
+ value,
+ };
+}
+
+/**
+ * Duration Field renders a TextField that accepts a number and a SelectField with a unit.
+ * If the entered value is a valid number, it'll propagate the computed value in seconds via
+ * onChange otherwise it'll just propogate whatever was entered as the value TextField.
+ */
+const DurationField: FunctionComponent = ({
+ value,
+ units = [UNIT.HOURS, UNIT.DAYS, UNIT.WEEKS],
+ onChange,
+ disabled,
+ name,
+ color,
+}) => {
+ const [selectedUnit, setSelectedUnit] = useState(
+ convertFromSeconds(value, units).unit
+ );
+
+ // If value changes, and selectedUnit has not been set, then set the value.
+ useEffect(() => {
+ if (!selectedUnit) {
+ setSelectedUnit(convertFromSeconds(value, units).unit);
+ }
+ }, [value]);
+
+ const elementCallbacks = useMemo(() => units.map(k => DURATION_UNIT_MAP[k]), [
+ units,
+ ]);
+
+ const { value: computedValue } = useMemo(
+ () => convertFromSeconds(value, units, selectedUnit),
+ [value, selectedUnit]
+ );
+
+ const handleValueChange = useCallback(
+ (e: ChangeEvent) => {
+ onChange(convertToSeconds(e.target.value, selectedUnit));
+ },
+ [onChange, selectedUnit]
+ );
+
+ const handleUnitChange = useCallback(
+ (e: ChangeEvent) => {
+ const unit = parseInt(e.target.value, 10);
+ setSelectedUnit(unit);
+ onChange(convertToSeconds(computedValue, unit));
+ },
+ [setSelectedUnit, onChange, computedValue]
+ );
+
+ return (
+
+
+ {elementCallbacks.length === 1 ? (
+
+ {elementCallbacks[0]}
+
+ ) : (
+
+ {elementCallbacks.map((unit, i) => {
+ const val = units[i];
+ return (
+
+ {unit}
+
+ );
+ })}
+
+ )}
+
+ );
+};
+
+export default DurationField;
diff --git a/src/core/client/ui/components/v2/DurationField/__snapshots__/DurationField.spec.tsx.snap b/src/core/client/ui/components/v2/DurationField/__snapshots__/DurationField.spec.tsx.snap
new file mode 100644
index 000000000..e64c3a6c8
--- /dev/null
+++ b/src/core/client/ui/components/v2/DurationField/__snapshots__/DurationField.spec.tsx.snap
@@ -0,0 +1,325 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`accepts invalid input 1`] = `
+
+
+
+
+
+ second
+
+
+
+
+ minute
+
+
+
+
+ hour
+
+
+
+
+`;
+
+exports[`renders correctly with default units 1`] = `
+
+
+
+
+
+ hour
+
+
+
+
+ day
+
+
+
+
+ week
+
+
+
+
+`;
+
+exports[`renders correctly with specified units 1`] = `
+
+
+
+
+
+ second
+
+
+
+
+ hour
+
+
+
+
+`;
+
+exports[`use best matching unit 1`] = `
+
+
+
+
+
+ second
+
+
+
+
+ minute
+
+
+
+
+ hour
+
+
+
+
+`;
+
+exports[`use initial unit if 0 1`] = `
+
+
+
+
+
+ second
+
+
+
+
+ minute
+
+
+
+
+ hour
+
+
+
+
+`;
diff --git a/src/core/client/ui/components/v2/DurationField/index.ts b/src/core/client/ui/components/v2/DurationField/index.ts
new file mode 100644
index 000000000..a259133cb
--- /dev/null
+++ b/src/core/client/ui/components/v2/DurationField/index.ts
@@ -0,0 +1 @@
+export { default, DURATION_UNIT } from "./DurationField";
diff --git a/src/core/client/ui/components/v2/FieldSet/FieldSet.css b/src/core/client/ui/components/v2/FieldSet/FieldSet.css
new file mode 100644
index 000000000..0ca1b7a65
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/FieldSet.css
@@ -0,0 +1,5 @@
+.root {
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
diff --git a/src/core/client/ui/components/v2/FieldSet/FieldSet.mdx b/src/core/client/ui/components/v2/FieldSet/FieldSet.mdx
new file mode 100644
index 000000000..52fdd24fc
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/FieldSet.mdx
@@ -0,0 +1,10 @@
+---
+name: FieldSet
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+
+# FieldSet
+
+Simple `fieldset` with removed styling for accessibility purposes.
diff --git a/src/core/client/ui/components/v2/FieldSet/FieldSet.spec.tsx b/src/core/client/ui/components/v2/FieldSet/FieldSet.spec.tsx
new file mode 100644
index 000000000..559840299
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/FieldSet.spec.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import FieldSet from "./FieldSet";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "content",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/FieldSet/FieldSet.tsx b/src/core/client/ui/components/v2/FieldSet/FieldSet.tsx
new file mode 100644
index 000000000..3526f54aa
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/FieldSet.tsx
@@ -0,0 +1,26 @@
+import cn from "classnames";
+import React, { AllHTMLAttributes, FunctionComponent, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./FieldSet.css";
+
+interface InnerProps extends AllHTMLAttributes {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const FieldSet: FunctionComponent = props => {
+ const { className, classes, forwardRef: ref, ...rest } = props;
+ const rootClassName = cn(classes.root, className);
+ return ;
+};
+const enhanced = withForwardRef(withStyles(styles)(FieldSet));
+export type FieldSetProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/FieldSet/__snapshots__/FieldSet.spec.tsx.snap b/src/core/client/ui/components/v2/FieldSet/__snapshots__/FieldSet.spec.tsx.snap
new file mode 100644
index 000000000..e8dda0396
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/__snapshots__/FieldSet.spec.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ content
+
+`;
diff --git a/src/core/client/ui/components/v2/FieldSet/index.ts b/src/core/client/ui/components/v2/FieldSet/index.ts
new file mode 100644
index 000000000..e9ef62e50
--- /dev/null
+++ b/src/core/client/ui/components/v2/FieldSet/index.ts
@@ -0,0 +1 @@
+export { default } from "./FieldSet";
diff --git a/src/core/client/ui/components/v2/Flex/Flex.css b/src/core/client/ui/components/v2/Flex/Flex.css
new file mode 100644
index 000000000..bebac3e69
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/Flex.css
@@ -0,0 +1,574 @@
+.root {
+}
+
+.flex {
+ display: flex;
+}
+
+.spacing-1 {
+ & > * {
+ margin: 0 var(--v2-spacing-1) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-1) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-1) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-1) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-2 {
+ & > * {
+ margin: 0 var(--v2-spacing-2) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-2) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-2) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-2) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-3 {
+ & > * {
+ margin: 0 var(--v2-spacing-3) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-3) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-3) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-3) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-4 {
+ & > * {
+ margin: 0 var(--v2-spacing-4) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-4) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-4) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-4) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-5 {
+ & > * {
+ margin: 0 var(--v2-spacing-5) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-5) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-5) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-5) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-6 {
+ & > * {
+ margin: 0 var(--v2-spacing-6) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-6) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-6) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-6) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-7 {
+ & > * {
+ margin: 0 var(--v2-spacing-7) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-7) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-7) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-7) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-8 {
+ & > * {
+ margin: 0 var(--v2-spacing-8) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-8) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-8) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-8) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.spacing-9 {
+ & > * {
+ margin: 0 var(--v2-spacing-9) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--v2-spacing-9) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--v2-spacing-9) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--v2-spacing-9) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.halfItemGutter {
+ & > * {
+ margin: 0 calc(0.5 * var(--mini-unit)) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 calc(0.5 * var(--mini-unit)) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 calc(0.5 * var(--mini-unit)) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: calc(0.5 * var(--mini-unit)) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.doubleItemGutter {
+ & > * {
+ margin: 0 calc(2 * var(--mini-unit)) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 calc(2 * var(--mini-unit)) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 calc(2 * var(--mini-unit)) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: calc(2 * var(--mini-unit)) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.itemGutter {
+ & > * {
+ margin: 0 var(--mini-unit) 0 0 !important;
+ }
+ &.directionRowReverse {
+ & > * {
+ margin: 0 0 0 var(--mini-unit) !important;
+ }
+ }
+ &.directionColumn {
+ & > * {
+ margin: 0 0 var(--mini-unit) 0 !important;
+ }
+ }
+ &.directionColumnReverse {
+ & > * {
+ margin: var(--mini-unit) 0 0 0 !important;
+ }
+ }
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.wrap {
+ flex-wrap: wrap;
+}
+
+.wrapReverse {
+ flex-wrap: wrap-reverse;
+}
+
+.wrap,
+.wrapReverse {
+ &:not(.directionColumn).itemGutter {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--mini-unit)) !important;
+ }
+ & > * {
+ margin-top: var(--mini-unit) !important;
+ }
+ }
+ &.directionColumn.itemGutter {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--mini-unit)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--mini-unit) !important;
+ }
+ }
+
+ &:not(.directionColumn).halfItemGutter {
+ &:not(:empty) {
+ margin-top: calc(-0.5 * var(--mini-unit)) !important;
+ }
+ & > * {
+ margin-top: calc(0.5 * var(--mini-unit)) !important;
+ }
+ }
+ &.directionColumn.halfItemGutter {
+ &:not(:empty) {
+ margin-left: calc(-0.5 * var(--mini-unit)) !important;
+ }
+ &.halfItemGutter > * {
+ margin-left: calc(0.5 * var(--mini-unit)) !important;
+ }
+ }
+
+ &:not(.directionColumn).doubleItemGutter {
+ &:not(:empty) {
+ margin-top: calc(-2 * var(--mini-unit)) !important;
+ }
+ & > * {
+ margin-top: calc(2 * var(--mini-unit)) !important;
+ }
+ }
+ &.directionColumn.doubleItemGutter {
+ &:not(:empty) {
+ margin-left: calc(-2 * var(--mini-unit)) !important;
+ }
+ &.doubleItemGutter > * {
+ margin-left: calc(2 * var(--mini-unit)) !important;
+ }
+ }
+
+ &:not(.directionColumn).tripleItemGutter {
+ &:not(:empty) {
+ margin-top: calc(-3 * var(--mini-unit)) !important;
+ }
+ & > * {
+ margin-top: calc(3 * var(--mini-unit)) !important;
+ }
+ }
+ &.directionColumn.tripleItemGutter {
+ &:not(:empty) {
+ margin-left: calc(-3 * var(--mini-unit)) !important;
+ }
+ &.tripleItemGutter > * {
+ margin-left: calc(3 * var(--mini-unit)) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-1 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-1)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-1) !important;
+ }
+ }
+ &.directionColumn.spacing-1 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-1)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-1) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-2 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-2)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-2) !important;
+ }
+ }
+ &.directionColumn.spacing-2 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-2)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-2) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-3 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-3)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-3) !important;
+ }
+ }
+ &.directionColumn.spacing-3 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-3)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-3) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-4 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-4)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-4) !important;
+ }
+ }
+ &.directionColumn.spacing-4 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-4)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-4) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-5 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-5)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-5) !important;
+ }
+ }
+ &.directionColumn.spacing-5 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-5)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-5) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-6 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-6)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-6) !important;
+ }
+ }
+ &.directionColumn.spacing-6 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-6)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-6) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-7 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-7)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-7) !important;
+ }
+ }
+ &.directionColumn.spacing-7 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-7)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-7) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-8 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-8)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-8) !important;
+ }
+ }
+ &.directionColumn.spacing-8 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-8)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-8) !important;
+ }
+ }
+
+ &:not(.directionColumn).spacing-9 {
+ &:not(:empty) {
+ margin-top: calc(-1 * var(--v2-spacing-9)) !important;
+ }
+ & > * {
+ margin-top: var(--v2-spacing-9) !important;
+ }
+ }
+ &.directionColumn.spacing-9 {
+ &:not(:empty) {
+ margin-left: calc(-1 * var(--v2-spacing-9)) !important;
+ }
+ &.itemGutter > * {
+ margin-left: var(--v2-spacing-9) !important;
+ }
+ }
+}
+
+.justifyFlexStart {
+ justify-content: flex-start;
+}
+.justifyFlexEnd {
+ justify-content: flex-end;
+}
+.justifyCenter {
+ justify-content: center;
+}
+.justifySpaceBetween {
+ justify-content: space-between;
+}
+.justifySpaceAround {
+ justify-content: space-around;
+}
+.justifySpaceEvenly {
+ justify-content: space-evenly;
+}
+
+.alignFlexStart {
+ align-items: flex-start;
+}
+.alignFlexEnd {
+ align-items: flex-end;
+}
+.alignCenter {
+ align-items: center;
+}
+.alignBaseline {
+ align-items: baseline;
+}
+.alignStretch {
+ align-items: stretch;
+}
+
+.directionRow {
+ flex-direction: row;
+}
+.directionColumn {
+ flex-direction: column;
+}
+.directionRowReverse {
+ flex-direction: row-reverse;
+}
+.directionColumnReverse {
+ flex-direction: column-reverse;
+}
diff --git a/src/core/client/ui/components/v2/Flex/Flex.mdx b/src/core/client/ui/components/v2/Flex/Flex.mdx
new file mode 100644
index 000000000..baf6177f4
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/Flex.mdx
@@ -0,0 +1,60 @@
+---
+name: Flex
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import Flex from "./Flex";
+import HorizontalGutter from "../HorizontalGutter";
+import Button from "../Button";
+
+# Flex
+
+`Flex` is a wrapper around `flexbox`.
+
+## Justify content
+
+
+ I'm centered
+
+
+## Align items
+
+
+
+ Push Me
+
+ Push Me
+
+
+ Push Me
+
+
+
+
+## Direction
+
+
+
+ Push Me
+ Push Me
+ Push Me
+
+
+
+## Item Gutter
+
+
+
+
+ Push Me
+ Push Me
+ Push Me
+
+
+ Push Me
+ Push Me
+ Push Me
+
+
+
diff --git a/src/core/client/ui/components/v2/Flex/Flex.spec.tsx b/src/core/client/ui/components/v2/Flex/Flex.spec.tsx
new file mode 100644
index 000000000..e1e6299d1
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/Flex.spec.tsx
@@ -0,0 +1,68 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Flex from "./Flex";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ justifyContent: "center",
+ alignItems: "center",
+ direction: "row",
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with wrap", () => {
+ const props: PropTypesOf = {
+ wrap: true,
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with wrap reverse", () => {
+ const props: PropTypesOf = {
+ wrap: "reverse",
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with item gutter", () => {
+ const props: PropTypesOf = {
+ itemGutter: true,
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders with half item gutter", () => {
+ const props: PropTypesOf = {
+ itemGutter: "half",
+ };
+ const renderer = TestRenderer.create(
+
+ Hello World
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Flex/Flex.tsx b/src/core/client/ui/components/v2/Flex/Flex.tsx
new file mode 100644
index 000000000..878e90fd9
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/Flex.tsx
@@ -0,0 +1,119 @@
+import cn from "classnames";
+import React, { FunctionComponent, Ref } from "react";
+
+import { pascalCase } from "coral-common/utils";
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Spacing } from "coral-ui/theme/variables";
+import { PropTypesOf } from "coral-ui/types";
+
+/** Needs to be loaded after styles, because Box styles have priority */
+import Box from "../Box";
+
+import styles from "./Flex.css";
+
+interface Props extends PropTypesOf {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+ id?: string;
+ role?: string;
+ justifyContent?:
+ | "flex-start"
+ | "flex-end"
+ | "center"
+ | "space-around"
+ | "space-between"
+ | "space-evenly";
+ alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch";
+ direction?: "row" | "column" | "row-reverse" | "column-reverse";
+ /** @deprecated use `spacing` instead */
+ itemGutter?: boolean | "half" | "double" | "triple";
+ /** Adds a gutter between items. Uses predefined sizes from design tokens */
+ spacing?: Spacing;
+ className?: string;
+ wrap?: boolean | "reverse";
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const Flex: FunctionComponent = props => {
+ const {
+ classes,
+ className,
+ justifyContent,
+ alignItems,
+ direction,
+ itemGutter,
+ wrap,
+ forwardRef,
+ children,
+ spacing,
+ ...rest
+ } = props;
+
+ const classObject: Record = {
+ [classes.itemGutter]: itemGutter === true,
+ [classes.halfItemGutter]: itemGutter === "half",
+ [classes.doubleItemGutter]: itemGutter === "double",
+ [classes.tripleItemGutter]: itemGutter === "triple",
+ [classes.wrap]: wrap === true,
+ [classes.wrapReverse]: wrap === "reverse",
+ };
+
+ if (justifyContent) {
+ classObject[
+ (classes as any)[`justify${pascalCase(justifyContent)}`]
+ ] = true;
+ }
+
+ if (alignItems) {
+ classObject[(classes as any)[`align${pascalCase(alignItems)}`]] = true;
+ }
+
+ if (direction) {
+ classObject[(classes as any)[`direction${pascalCase(direction)}`]] = true;
+ }
+
+ const rootClassNames: string = cn(classes.root, className);
+ const flexClassNames: string = cn(
+ classes.flex,
+ classObject,
+ (itemGutter || spacing) && "gutter",
+ spacing && (classes as any)[`spacing-${spacing}`]
+ );
+
+ // text nodes can't be modified with css, so replace them with spans.
+ // Readd spaces at the beginning or end of text nodes because
+ // flex removes it.
+ const content = React.Children.map(children, child => {
+ if (typeof child === "string") {
+ return {child.replace(/^ +| +$/g, "\xa0")} ;
+ }
+ return child;
+ });
+
+ if (wrap && itemGutter) {
+ // The first div is required to support nested `Flex` components with itemGutters.
+ return (
+
+ {content}
+
+ );
+ }
+ return (
+
+ {content}
+
+ );
+};
+
+const enhanced = withForwardRef(withStyles(styles)(Flex));
+export default enhanced;
+export type FlexProps = PropTypesOf;
diff --git a/src/core/client/ui/components/v2/Flex/__snapshots__/Flex.spec.tsx.snap b/src/core/client/ui/components/v2/Flex/__snapshots__/Flex.spec.tsx.snap
new file mode 100644
index 000000000..5f915908a
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/__snapshots__/Flex.spec.tsx.snap
@@ -0,0 +1,51 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
+
+exports[`renders with half item gutter 1`] = `
+
+`;
+
+exports[`renders with item gutter 1`] = `
+
+`;
+
+exports[`renders with wrap 1`] = `
+
+`;
+
+exports[`renders with wrap reverse 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/Flex/index.ts b/src/core/client/ui/components/v2/Flex/index.ts
new file mode 100644
index 000000000..434836f6d
--- /dev/null
+++ b/src/core/client/ui/components/v2/Flex/index.ts
@@ -0,0 +1 @@
+export { default, FlexProps } from "./Flex";
diff --git a/src/core/client/ui/components/v2/FormField/FormField.css b/src/core/client/ui/components/v2/FormField/FormField.css
new file mode 100644
index 000000000..c3a2af639
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/FormField.css
@@ -0,0 +1,2 @@
+.root {
+}
diff --git a/src/core/client/ui/components/v2/FormField/FormField.mdx b/src/core/client/ui/components/v2/FormField/FormField.mdx
new file mode 100644
index 000000000..f6b369861
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/FormField.mdx
@@ -0,0 +1,65 @@
+---
+name: FormField
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import { Field } from "react-final-form";
+import { Label, FormFieldHeader, TextField, FormFieldDescription, HelperText, FormField, TextFieldWithValidation, DurationField, ValidationMessage } from '../'
+
+# FormField
+
+`FormField` is to be used with Form Components: `FormFieldDescription`, `FormFieldHeader`, `TextField`, `HelperText`, etc.
+These components manage the gutters between inner elements to ensure consistent spacing.
+
+- `FormField` should wrap a form input and its label, along with any field descriptions or helper text
+- `FormFieldHeader` wraps a form label and its helper text. Not necessary if there's only a label
+- `FormFieldDescription` is a general description or explanation of the field or series of fields
+- `HelperText` is clarifying information or instructions, that follows a label
+- `TextFieldWithValidation` wraps a text field and its validation
+
+## Justify content
+
+
+ A simple form field
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
+ This is a description of this form field
+
+ A form field with helper text
+ This is some helper text or instructions
+
+
+ {({ input, meta }) => (
+
+ )}
+
+
+
+ A form field with a different input type
+
+ {({ input, meta }) => (
+
+
+
+
+ )}
+
+
+
diff --git a/src/core/client/ui/components/v2/FormField/FormField.spec.tsx b/src/core/client/ui/components/v2/FormField/FormField.spec.tsx
new file mode 100644
index 000000000..52b95b7d6
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/FormField.spec.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import FormField from "../FormField";
+import HelperText from "../HelperText";
+import Label from "../Label";
+import TextField from "../TextField";
+
+it("renders correctly", () => {
+ const renderer = TestRenderer.create(
+ Form Components should go here
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("works with multiple form components", () => {
+ const renderer = TestRenderer.create(
+
+ Username
+
+ An identifier displayed on your comments. You may use “_” and “.”
+
+
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/FormField/FormField.tsx b/src/core/client/ui/components/v2/FormField/FormField.tsx
new file mode 100644
index 000000000..d44afff6a
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/FormField.tsx
@@ -0,0 +1,32 @@
+import cn from "classnames";
+import React, { FunctionComponent, ReactNode } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+import { Omit, PropTypesOf } from "coral-ui/types";
+
+import HorizontalGutter from "coral-ui/components/HorizontalGutter";
+
+import styles from "./FormField.css";
+
+interface Props extends Omit, "ref"> {
+ children: ReactNode;
+ classes: typeof styles;
+ className?: string;
+}
+
+const FormField: FunctionComponent = props => {
+ const { classes, className, children, ...rest } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+const enhanced = withStyles(styles)(FormField);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/FormField/__snapshots__/FormField.spec.tsx.snap b/src/core/client/ui/components/v2/FormField/__snapshots__/FormField.spec.tsx.snap
new file mode 100644
index 000000000..6cadb86a0
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/__snapshots__/FormField.spec.tsx.snap
@@ -0,0 +1,35 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ Form Components should go here
+
+`;
+
+exports[`works with multiple form components 1`] = `
+
+
+ Username
+
+
+ An identifier displayed on your comments. You may use “_” and “.”
+
+
+
+
+
+`;
diff --git a/src/core/client/ui/components/v2/FormField/index.ts b/src/core/client/ui/components/v2/FormField/index.ts
new file mode 100644
index 000000000..e2d6f74d4
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormField/index.ts
@@ -0,0 +1 @@
+export { default } from "./FormField";
diff --git a/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.css b/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.css
new file mode 100644
index 000000000..8c2cff918
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.css
@@ -0,0 +1,7 @@
+.root {
+ color: var(--v2-palette-configure-description);
+ line-height: var(--v2-line-height-body-short);
+ font-size: var(--v2-font-size-3);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+}
diff --git a/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.tsx b/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.tsx
new file mode 100644
index 000000000..a986748df
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldDescription/FormFieldDescription.tsx
@@ -0,0 +1,17 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import styles from "./FormFieldDescription.css";
+
+interface Props {
+ className?: string;
+}
+
+const FormFieldDescription: FunctionComponent = ({
+ children,
+ className,
+}) => {
+ return {children}
;
+};
+
+export default FormFieldDescription;
diff --git a/src/core/client/ui/components/v2/FormFieldDescription/index.ts b/src/core/client/ui/components/v2/FormFieldDescription/index.ts
new file mode 100644
index 000000000..71a77701f
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldDescription/index.ts
@@ -0,0 +1 @@
+export { default } from "./FormFieldDescription";
diff --git a/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.css b/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.css
new file mode 100644
index 000000000..c3a2af639
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.css
@@ -0,0 +1,2 @@
+.root {
+}
diff --git a/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.tsx b/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.tsx
new file mode 100644
index 000000000..e08b15daf
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldHeader/FormFieldHeader.tsx
@@ -0,0 +1,32 @@
+import cn from "classnames";
+import React, { FunctionComponent, ReactNode } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+import { Omit, PropTypesOf } from "coral-ui/types";
+
+import HorizontalGutter from "coral-ui/components/HorizontalGutter";
+
+import styles from "./FormFieldHeader.css";
+
+interface Props extends Omit, "ref"> {
+ children: ReactNode;
+ classes: typeof styles;
+ className?: string;
+}
+
+const FormFieldHeader: FunctionComponent = props => {
+ const { classes, className, children, ...rest } = props;
+
+ return (
+
+ {children}
+
+ );
+};
+
+const enhanced = withStyles(styles)(FormFieldHeader);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/FormFieldHeader/index.ts b/src/core/client/ui/components/v2/FormFieldHeader/index.ts
new file mode 100644
index 000000000..a7f537ae7
--- /dev/null
+++ b/src/core/client/ui/components/v2/FormFieldHeader/index.ts
@@ -0,0 +1 @@
+export { default } from "./FormFieldHeader";
diff --git a/src/core/client/ui/components/v2/HelperText/HelperText.css b/src/core/client/ui/components/v2/HelperText/HelperText.css
new file mode 100644
index 000000000..0dd1ce851
--- /dev/null
+++ b/src/core/client/ui/components/v2/HelperText/HelperText.css
@@ -0,0 +1,7 @@
+.root {
+ color: var(--v2-palette-input-helper);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-body-short);
+}
diff --git a/src/core/client/ui/components/v2/HelperText/HelperText.tsx b/src/core/client/ui/components/v2/HelperText/HelperText.tsx
new file mode 100644
index 000000000..790e87a75
--- /dev/null
+++ b/src/core/client/ui/components/v2/HelperText/HelperText.tsx
@@ -0,0 +1,14 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import styles from "./HelperText.css";
+
+interface Props {
+ className?: string;
+}
+
+const HelperText: FunctionComponent = ({ children, className }) => {
+ return {children}
;
+};
+
+export default HelperText;
diff --git a/src/core/client/ui/components/v2/HelperText/index.ts b/src/core/client/ui/components/v2/HelperText/index.ts
new file mode 100644
index 000000000..97707a020
--- /dev/null
+++ b/src/core/client/ui/components/v2/HelperText/index.ts
@@ -0,0 +1 @@
+export { default } from "./HelperText";
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.css b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.css
new file mode 100644
index 000000000..f5d44939f
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.css
@@ -0,0 +1,85 @@
+.root {
+ display: block;
+ border: 0;
+ padding: 0;
+
+ & > *:last-child {
+ margin: 0 !important;
+ }
+}
+
+.half {
+ & > * {
+ margin: 0 0 calc(0.5 * var(--mini-unit)) 0 !important;
+ }
+}
+.full {
+ & > * {
+ margin: 0 0 var(--mini-unit) 0 !important;
+ }
+}
+.oneAndAHalf {
+ & > * {
+ margin: 0 0 calc(1.5 * var(--mini-unit)) 0 !important;
+ }
+}
+.double {
+ & > * {
+ margin: 0 0 calc(2 * var(--mini-unit)) 0 !important;
+ }
+}
+.triple {
+ & > * {
+ margin: 0 0 calc(3 * var(--mini-unit)) 0 !important;
+ }
+}
+.spacing-1 {
+ & > * {
+ margin: 0 0 var(--spacing-1) 0 !important;
+ }
+}
+.spacing-2 {
+ & > * {
+ margin: 0 0 var(--spacing-2) 0 !important;
+ }
+}
+.spacing-3 {
+ & > * {
+ margin: 0 0 var(--spacing-3) 0 !important;
+ }
+}
+.spacing-1 {
+ & > * {
+ margin: 0 0 var(--spacing-1) 0 !important;
+ }
+}
+.spacing-4 {
+ & > * {
+ margin: 0 0 var(--spacing-4) 0 !important;
+ }
+}
+.spacing-5 {
+ & > * {
+ margin: 0 0 var(--spacing-5) 0 !important;
+ }
+}
+.spacing-6 {
+ & > * {
+ margin: 0 0 var(--spacing-6) 0 !important;
+ }
+}
+.spacing-7 {
+ & > * {
+ margin: 0 0 var(--spacing-7) 0 !important;
+ }
+}
+.spacing-8 {
+ & > * {
+ margin: 0 0 var(--spacing-8) 0 !important;
+ }
+}
+.spacing-9 {
+ & > * {
+ margin: 0 0 var(--spacing-9) 0 !important;
+ }
+}
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.mdx b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.mdx
new file mode 100644
index 000000000..40a7908ad
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.mdx
@@ -0,0 +1,36 @@
+---
+name: HorizontalGutter
+menu: UI Kit
+---
+
+import { Playground } from "docz";
+import HorizontalGutter from "./HorizontalGutter";
+import Button from "../Button";
+
+# Spinner
+
+## Usage
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.spec.tsx b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.spec.tsx
new file mode 100644
index 000000000..470baa72d
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.spec.tsx
@@ -0,0 +1,22 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import HorizontalGutter from "./HorizontalGutter";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders double size", () => {
+ const props: PropTypesOf = {
+ size: "double",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.tsx b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.tsx
new file mode 100644
index 000000000..7efb764a8
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/HorizontalGutter.tsx
@@ -0,0 +1,72 @@
+import cn from "classnames";
+import React, { FunctionComponent, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Spacing } from "coral-ui/theme/variables";
+import { PropTypesOf } from "coral-ui/types";
+
+/** Needs to be loaded after styles, because Box styles have priority */
+import Box from "../Box";
+
+import styles from "./HorizontalGutter.css";
+
+interface Props extends PropTypesOf {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+
+ /** @deprecated use `spacing` instead */
+ size?: "half" | "full" | "double" | "triple" | "oneAndAHalf";
+
+ /** Choose gutter size, uses predefined sizes from design tokens */
+ spacing?: Spacing;
+
+ /** The name of the HorizontalGutter to render */
+ children?: React.ReactNode;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+
+ /**
+ * The container used for the root node.
+ * Either a string to use a DOM element, a component, or an element.
+ * By default, it maps the variant to a good default headline component.
+ */
+ container?: React.ReactElement | React.ComponentType | string;
+}
+
+const HorizontalGutter: FunctionComponent = props => {
+ const {
+ classes,
+ className,
+ size,
+ forwardRef,
+ container,
+ spacing,
+ ...rest
+ } = props;
+ const rootClassName = cn(
+ classes.root,
+ className,
+ spacing ? (classes as any)[`spacing-${spacing}`] : classes[size!]
+ );
+
+ const innerProps = {
+ className: rootClassName,
+ ref: forwardRef,
+ container,
+ ...rest,
+ };
+ return ;
+};
+
+HorizontalGutter.defaultProps = {
+ size: "full",
+ container: "div",
+} as Partial;
+
+const enhanced = withForwardRef(withStyles(styles)(HorizontalGutter));
+export type HorizontalGutterProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/__snapshots__/HorizontalGutter.spec.tsx.snap b/src/core/client/ui/components/v2/HorizontalGutter/__snapshots__/HorizontalGutter.spec.tsx.snap
new file mode 100644
index 000000000..af7883930
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/__snapshots__/HorizontalGutter.spec.tsx.snap
@@ -0,0 +1,13 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
+
+exports[`renders double size 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/HorizontalGutter/index.ts b/src/core/client/ui/components/v2/HorizontalGutter/index.ts
new file mode 100644
index 000000000..74ebbbd3c
--- /dev/null
+++ b/src/core/client/ui/components/v2/HorizontalGutter/index.ts
@@ -0,0 +1 @@
+export { default, HorizontalGutterProps } from "./HorizontalGutter";
diff --git a/src/core/client/ui/components/v2/Icon/Icon.css b/src/core/client/ui/components/v2/Icon/Icon.css
new file mode 100644
index 000000000..e5c21e976
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/Icon.css
@@ -0,0 +1,58 @@
+.root {
+ font-family: "Material Icons";
+ speak: none;
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ overflow: hidden;
+ vertical-align: middle;
+ display: inline-block;
+ letter-spacing: 0;
+ word-break: initial;
+
+ /* Enable Ligatures */
+ font-feature-settings: "liga";
+ font-variant-ligatures: "discretionary-ligatures";
+
+ /* Support for Safari and Chrome. */
+ text-rendering: optimizeLegibility;
+
+ /* Better Font Rendering */
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.xs {
+ font-size: 10px;
+ width: 10px;
+}
+
+.sm {
+ font-size: 14px;
+ width: 14px;
+}
+.md {
+ font-size: 18px;
+ width: 18px;
+}
+.lg {
+ font-size: 24px;
+ width: 24px;
+}
+.xl {
+ font-size: 36px;
+ width: 36px;
+}
+
+.colorPrimary {
+ color: var(--v2-colors-teal-700);
+}
+.colorError {
+ color: var(--v2-colors-red-500);
+}
+
+.colorSuccess {
+ color: var(--v2-colors-green-500);
+}
diff --git a/src/core/client/ui/components/v2/Icon/Icon.mdx b/src/core/client/ui/components/v2/Icon/Icon.mdx
new file mode 100644
index 000000000..83428c28b
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/Icon.mdx
@@ -0,0 +1,21 @@
+---
+name: Icon
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import Icon from './Icon'
+
+# Icon
+
+Renders an icon.
+
+Checkout available icons https://material.io/tools/icons/
+
+## Basic usage
+
+ face
+ face
+ face
+ face
+
diff --git a/src/core/client/ui/components/v2/Icon/Icon.spec.tsx b/src/core/client/ui/components/v2/Icon/Icon.spec.tsx
new file mode 100644
index 000000000..b4175a5b2
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/Icon.spec.tsx
@@ -0,0 +1,23 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-framework/types";
+
+import Icon from "./Icon";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ children: "face",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders correctly with specified size", () => {
+ const props: PropTypesOf = {
+ size: "lg",
+ children: "bookmark",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Icon/Icon.tsx b/src/core/client/ui/components/v2/Icon/Icon.tsx
new file mode 100644
index 000000000..601624fb6
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/Icon.tsx
@@ -0,0 +1,60 @@
+import cn from "classnames";
+import React, { FunctionComponent, HTMLAttributes, Ref } from "react";
+
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./Icon.css";
+
+interface Props extends HTMLAttributes {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles;
+
+ size?: "xs" | "sm" | "md" | "lg" | "xl";
+
+ /**
+ * The color of the component. It supports those theme colors that make sense for this component.
+ */
+ color?: "inherit" | "primary" | "error" | "success";
+
+ /** The name of the icon to render */
+ children: string;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const Icon: FunctionComponent = props => {
+ const { classes, className, size, color, forwardRef, ...rest } = props;
+
+ const rootClassName = cn(
+ classes.root,
+ classes[size !== undefined ? size : "sm"],
+ {
+ [classes.colorPrimary]: color === "primary",
+ [classes.colorError]: color === "error",
+ [classes.colorSuccess]: color === "success",
+ },
+ className
+ );
+ return (
+
+ );
+};
+
+Icon.defaultProps = {
+ size: "sm",
+ color: "inherit",
+} as Partial;
+
+const enhanced = withForwardRef(withStyles(styles)(Icon));
+export type IconProps = PropTypesOf;
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Icon/__snapshots__/Icon.spec.tsx.snap b/src/core/client/ui/components/v2/Icon/__snapshots__/Icon.spec.tsx.snap
new file mode 100644
index 000000000..a56052568
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/__snapshots__/Icon.spec.tsx.snap
@@ -0,0 +1,19 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ face
+
+`;
+
+exports[`renders correctly with specified size 1`] = `
+
+ bookmark
+
+`;
diff --git a/src/core/client/ui/components/v2/Icon/index.ts b/src/core/client/ui/components/v2/Icon/index.ts
new file mode 100644
index 000000000..d3ba5da55
--- /dev/null
+++ b/src/core/client/ui/components/v2/Icon/index.ts
@@ -0,0 +1 @@
+export { default, IconProps } from "./Icon";
diff --git a/src/core/client/ui/components/v2/Label/Label.css b/src/core/client/ui/components/v2/Label/Label.css
new file mode 100644
index 000000000..100976323
--- /dev/null
+++ b/src/core/client/ui/components/v2/Label/Label.css
@@ -0,0 +1,9 @@
+.root {
+ color: var(--v2-palette-input-label);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-reset);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-family: var(--v2-font-family-primary);
+ padding-left: 0;
+ display: block;
+}
diff --git a/src/core/client/ui/components/v2/Label/Label.tsx b/src/core/client/ui/components/v2/Label/Label.tsx
new file mode 100644
index 000000000..cccf50753
--- /dev/null
+++ b/src/core/client/ui/components/v2/Label/Label.tsx
@@ -0,0 +1,19 @@
+import React, { FunctionComponent, LabelHTMLAttributes } from "react";
+
+import styles from "./Label.css";
+
+interface Props extends LabelHTMLAttributes {
+ className?: string;
+ component?: "legend" | "p";
+}
+
+const Label: FunctionComponent = ({ children, component, ...rest }) => {
+ const Component = component || "label";
+ return (
+
+ {children}
+
+ );
+};
+
+export default Label;
diff --git a/src/core/client/ui/components/v2/Label/index.ts b/src/core/client/ui/components/v2/Label/index.ts
new file mode 100644
index 000000000..8c8faebf8
--- /dev/null
+++ b/src/core/client/ui/components/v2/Label/index.ts
@@ -0,0 +1 @@
+export { default } from "./Label";
diff --git a/src/core/client/ui/components/v2/Marker/Count.css b/src/core/client/ui/components/v2/Marker/Count.css
new file mode 100644
index 000000000..86f07c13f
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Count.css
@@ -0,0 +1,14 @@
+.root {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: 0.8125rem;
+ letter-spacing: calc(-0.35em / 13);
+
+ border-left: 1px solid currentColor;
+ margin-left: calc(0.5 * var(--mini-unit));
+ margin-right: calc(-0.25 * var(--mini-unit));
+ padding-top: 2px;
+ padding-bottom: 2px;
+ padding-left: calc(0.5 * var(--mini-unit));
+ white-space: nowrap;
+}
diff --git a/src/core/client/ui/components/v2/Marker/Count.spec.tsx b/src/core/client/ui/components/v2/Marker/Count.spec.tsx
new file mode 100644
index 000000000..7b81152f5
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Count.spec.tsx
@@ -0,0 +1,15 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Count from "./Count";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ children: "30",
+ };
+ const renderer = TestRenderer.create(Hello );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Marker/Count.tsx b/src/core/client/ui/components/v2/Marker/Count.tsx
new file mode 100644
index 000000000..96f13ae8c
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Count.tsx
@@ -0,0 +1,29 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Count.css";
+
+interface Props {
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ children: React.ReactNode;
+}
+
+const Count: FunctionComponent = props => {
+ const { className, children, classes, ...rest } = props;
+ const rootClassName = cn(classes.root, className);
+
+ return (
+
+ {children}
+
+ );
+};
+
+const enhanced = withStyles(styles)(Count);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Marker/Marker.css b/src/core/client/ui/components/v2/Marker/Marker.css
new file mode 100644
index 000000000..0f5e08967
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Marker.css
@@ -0,0 +1,33 @@
+.root {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-semi-bold);
+ font-size: 0.8125rem;
+ letter-spacing: calc(-0.35em / 13);
+
+ color: var(--v2-palette-marker-reported);
+ border: 1px solid currentColor;
+ border-radius: 20px;
+ padding: 1px var(--mini-unit);
+ white-space: nowrap;
+}
+
+.colorReported {
+ color: var(--v2-palette-marker-reported);
+}
+
+.colorPending {
+ color: var(--v2-palette-marker-pending);
+}
+
+.variantRegular {
+}
+
+.variantFilled {
+ &.colorReported {
+ background-color: var(--v2-palette-marker-reported);
+ }
+
+ &.colorPending {
+ background-color: var(--v2-palette-marker-pending);
+ }
+}
diff --git a/src/core/client/ui/components/v2/Marker/Marker.mdx b/src/core/client/ui/components/v2/Marker/Marker.mdx
new file mode 100644
index 000000000..7a5138a8f
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Marker.mdx
@@ -0,0 +1,43 @@
+---
+name: Marker
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import Marker from "./Marker";
+import Count from "./Count";
+import HorizontalGutter from "../HorizontalGutter";
+import Flex from "../Flex";
+
+# Marker
+
+## Basic Use
+
+
+
+
+ Toxic
+ Karma
+ Spam
+ Banned Word
+
+ With a count 1
+
+
+
+ Premod
+ Link
+
+
+
+ Spam 2
+
+
+ Suspect Word
+
+
+ Offensive 1
+
+
+
+
diff --git a/src/core/client/ui/components/v2/Marker/Marker.spec.tsx b/src/core/client/ui/components/v2/Marker/Marker.spec.tsx
new file mode 100644
index 000000000..215c65a7a
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Marker.spec.tsx
@@ -0,0 +1,17 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Marker from "./Marker";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ color: "reported",
+ variant: "filled",
+ children: "Spam",
+ };
+ const renderer = TestRenderer.create(Hello );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Marker/Marker.tsx b/src/core/client/ui/components/v2/Marker/Marker.tsx
new file mode 100644
index 000000000..3a6063d1c
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/Marker.tsx
@@ -0,0 +1,46 @@
+import cn from "classnames";
+import React, { FunctionComponent } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Marker.css";
+
+interface Props {
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ children: React.ReactNode;
+ /**
+ * The color of the component. It supports those theme colors that make sense for this component.
+ */
+ color?: "reported" | "pending";
+
+ variant?: "regular" | "filled";
+}
+
+const Marker: FunctionComponent = props => {
+ const { className, children, classes, color, variant, ...rest } = props;
+
+ const rootClassName = cn(classes.root, className, {
+ [classes.colorReported]: color === "reported",
+ [classes.colorPending]: color === "pending",
+ [classes.variantRegular]: variant === "regular",
+ [classes.variantFilled]: variant === "filled",
+ });
+
+ return (
+
+ {children}
+
+ );
+};
+
+Marker.defaultProps = {
+ color: "pending",
+ variant: "regular",
+};
+
+const enhanced = withStyles(styles)(Marker);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Marker/__snapshots__/Count.spec.tsx.snap b/src/core/client/ui/components/v2/Marker/__snapshots__/Count.spec.tsx.snap
new file mode 100644
index 000000000..a0dfbda82
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/__snapshots__/Count.spec.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ Hello
+
+`;
diff --git a/src/core/client/ui/components/v2/Marker/__snapshots__/Marker.spec.tsx.snap b/src/core/client/ui/components/v2/Marker/__snapshots__/Marker.spec.tsx.snap
new file mode 100644
index 000000000..b34064efa
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/__snapshots__/Marker.spec.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ Hello
+
+`;
diff --git a/src/core/client/ui/components/v2/Marker/index.ts b/src/core/client/ui/components/v2/Marker/index.ts
new file mode 100644
index 000000000..2622c15bd
--- /dev/null
+++ b/src/core/client/ui/components/v2/Marker/index.ts
@@ -0,0 +1,2 @@
+export { default, default as Marker } from "./Marker";
+export { default as Count } from "./Count";
diff --git a/src/core/client/ui/components/v2/Message/Message.css b/src/core/client/ui/components/v2/Message/Message.css
new file mode 100644
index 000000000..99ad852c3
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/Message.css
@@ -0,0 +1,43 @@
+.root {
+ position: relative;
+ display: inline-flex;
+ justify-content: flex-start;
+ align-items: center;
+ padding: var(--v2-spacing-1) var(--v2-spacing-2);
+ box-sizing: border-box;
+ border-radius: var(--round-corners);
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-bold);
+ font-size: var(--v2-font-size-2);
+ line-height: var(--v2-line-height-title);
+}
+
+.colorGrey {
+ background-color: var(--palette-common-white);
+ border-color: var(--palette-grey-main);
+ color: var(--palette-grey-main);
+}
+
+.colorDark {
+ background-color: var(--palette-text-primary);
+ border-width: 0px;
+ color: var(--palette-text-light);
+}
+
+.colorError {
+ background-color: var(--v2-palette-message-error-background);
+ color: var(--v2-palette-message-error-foreground);
+}
+
+.colorPrimary {
+ background-color: var(--palette-primary-light);
+ border-color: var(--palette-primary-darkest);
+ border-width: 0px;
+ border-left-width: calc(0.5 * var(--mini-unit));
+ color: var(--palette-text-light);
+}
+
+.fullWidth {
+ display: flex;
+ width: 100%;
+}
diff --git a/src/core/client/ui/components/v2/Message/Message.mdx b/src/core/client/ui/components/v2/Message/Message.mdx
new file mode 100644
index 000000000..5baa5aa78
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/Message.mdx
@@ -0,0 +1,38 @@
+---
+name: Message
+menu: UI Kit
+---
+
+import { Playground } from "docz";
+import Message from "./Message";
+import MessageIcon from "./MessageIcon";
+import HorizontalGutter from "../HorizontalGutter";
+
+# Message
+
+## Basic Use
+
+
+
+ This is a message
+
+ Contrary to popular belief, Lorem Ipsum is not simply random text.
+
+
+ Contrary to popular belief, Lorem Ipsum is not simply random text.
+
+
+ Contrary to popular belief, Lorem Ipsum is not simply random text.
+
+
+
+
+## Usage with icon
+
+
+
+
+ alarm Edit: 1 min 23 secs Remaining
+
+
+
diff --git a/src/core/client/ui/components/v2/Message/Message.spec.tsx b/src/core/client/ui/components/v2/Message/Message.spec.tsx
new file mode 100644
index 000000000..2e02522b6
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/Message.spec.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import Message from "./Message";
+import MessageIcon from "./MessageIcon";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ children: "Hello World",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
+
+it("renders icon", () => {
+ const renderer = TestRenderer.create(
+
+ alert Alert Message
+
+ );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/Message/Message.tsx b/src/core/client/ui/components/v2/Message/Message.tsx
new file mode 100644
index 000000000..b07db57a4
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/Message.tsx
@@ -0,0 +1,59 @@
+import cn from "classnames";
+import React, { FunctionComponent, ReactNode } from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import styles from "./Message.css";
+
+export interface MessageProps {
+ /**
+ * The content of the component.
+ */
+ children: ReactNode;
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /*
+ * If set renders a full width message
+ */
+ fullWidth?: boolean;
+ /*
+ * Name of color, "grey" stays by default - common gray one
+ */
+ color?: "error" | "grey" | "primary" | "dark";
+}
+
+const Message: FunctionComponent = props => {
+ const { className, classes, fullWidth, children, color, ...rest } = props;
+
+ const rootClassName = cn(
+ classes.root,
+ {
+ [classes.colorGrey]: color === "grey",
+ [classes.colorError]: color === "error",
+ [classes.colorPrimary]: color === "primary",
+ [classes.colorDark]: color === "dark",
+ [classes.fullWidth]: fullWidth,
+ },
+ className
+ );
+
+ return (
+
+ {children}
+
+ );
+};
+
+Message.defaultProps = {
+ color: "grey",
+ fullWidth: false,
+};
+
+const enhanced = withStyles(styles)(Message);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Message/MessageIcon.css b/src/core/client/ui/components/v2/Message/MessageIcon.css
new file mode 100644
index 000000000..a6ebb20be
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/MessageIcon.css
@@ -0,0 +1,8 @@
+.root {
+ align-self: flex-start;
+ margin-top: 1px;
+ flex-shrink: 0;
+ &:first-child {
+ margin-right: calc(0.5 * var(--mini-unit));
+ }
+}
diff --git a/src/core/client/ui/components/v2/Message/MessageIcon.tsx b/src/core/client/ui/components/v2/Message/MessageIcon.tsx
new file mode 100644
index 000000000..d6b2eed38
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/MessageIcon.tsx
@@ -0,0 +1,37 @@
+import cn from "classnames";
+import React, { FunctionComponent, HTMLAttributes, Ref } from "react";
+
+import Icon, { IconProps } from "coral-ui/components/Icon";
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { Omit } from "coral-ui/types";
+
+import styles from "./MessageIcon.css";
+
+interface Props extends Omit, "color"> {
+ /**
+ * This prop can be used to add custom classnames.
+ * It is handled by the `withStyles `HOC.
+ */
+ classes: typeof styles & IconProps["classes"];
+
+ size?: IconProps["size"];
+
+ /** The name of the icon to render */
+ children: string;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+export const MessageIcon: FunctionComponent = props => {
+ const { classes, className, forwardRef, ...rest } = props;
+ const rootClassName = cn(classes.root, className);
+ return ;
+};
+
+MessageIcon.defaultProps = {
+ size: "sm",
+};
+
+const enhanced = withForwardRef(withStyles(styles)(MessageIcon));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Message/__snapshots__/Message.spec.tsx.snap b/src/core/client/ui/components/v2/Message/__snapshots__/Message.spec.tsx.snap
new file mode 100644
index 000000000..2a977f72b
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/__snapshots__/Message.spec.tsx.snap
@@ -0,0 +1,23 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+ Hello World
+
+`;
+
+exports[`renders icon 1`] = `
+
+
+ alert
+
+ Alert Message
+
+`;
diff --git a/src/core/client/ui/components/v2/Message/index.ts b/src/core/client/ui/components/v2/Message/index.ts
new file mode 100644
index 000000000..84f6b9009
--- /dev/null
+++ b/src/core/client/ui/components/v2/Message/index.ts
@@ -0,0 +1,2 @@
+export { default, default as Message } from "./Message";
+export { default as MessageIcon } from "./MessageIcon";
diff --git a/src/core/client/ui/components/v2/Modal/Modal.css b/src/core/client/ui/components/v2/Modal/Modal.css
new file mode 100644
index 000000000..92b04ca37
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/Modal.css
@@ -0,0 +1,32 @@
+.root {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+ z-index: var(--zindex-modal);
+}
+
+.scroll {
+ pointer-events: none;
+ position: relative;
+ overflow-y: auto;
+ width: 100%;
+ height: 100%;
+}
+
+.alignContainer1 {
+ display: table;
+ margin: 0 auto;
+ height: 100%;
+}
+
+.alignContainer2 {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.wrapper {
+ pointer-events: all;
+}
diff --git a/src/core/client/ui/components/v2/Modal/Modal.mdx b/src/core/client/ui/components/v2/Modal/Modal.mdx
new file mode 100644
index 000000000..61fd1c278
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/Modal.mdx
@@ -0,0 +1,66 @@
+---
+name: Modal
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import { useState, useCallback } from "react";
+
+import Button from "../Button";
+import Card, { CardCloseButton } from "../Card";
+import Typography from "../Typography";
+import Flex from "../Flex";
+import HorizontalGutter from "../HorizontalGutter";
+import Modal from "./Modal";
+
+import styles from "./Modal.mdx.css";
+
+# Modal
+
+## Basic usage
+
+
+ {() => {
+ const [open, setOpen] = useState(false);
+ const show = useCallback(() => setOpen(true));
+ const hide = useCallback(() => setOpen(false));
+ return (
+ <>
+
+ Show Modal
+
+
+ {({ firstFocusableRef, lastFocusableRef }) => (
+
+
+
+
+
+ Are you sure you want to ban ButFirstCoffee ?
+
+
+ Once banned, this user will no longer be able to comment,
+ use reactions, or report comments.
+
+
+
+
+ Cancel
+
+
+ Ban User
+
+
+
+
+ )}
+
+ >
+ );
+ }}
+
diff --git a/src/core/client/ui/components/v2/Modal/Modal.mdx.css b/src/core/client/ui/components/v2/Modal/Modal.mdx.css
new file mode 100644
index 000000000..9b2098d45
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/Modal.mdx.css
@@ -0,0 +1,3 @@
+.card {
+ max-width: 500px;
+}
diff --git a/src/core/client/ui/components/v2/Modal/Modal.spec.tsx b/src/core/client/ui/components/v2/Modal/Modal.spec.tsx
new file mode 100644
index 000000000..02fa4f970
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/Modal.spec.tsx
@@ -0,0 +1,90 @@
+import { noop } from "lodash";
+import React from "react";
+import TestRenderer, { ReactTestRenderer } from "react-test-renderer";
+import sinon from "sinon";
+
+import Modal from "./Modal";
+
+const createNodeMock = () => ({
+ focus: noop,
+});
+
+it("renders correctly", () => {
+ expect(document.body.lastChild).toBeNull();
+ let testRenderer: ReactTestRenderer;
+ TestRenderer.act(() => {
+ testRenderer = TestRenderer.create(
+
+ Test
+ ,
+ { createNodeMock }
+ );
+ });
+ expect(testRenderer!.toJSON()).toBeNull();
+ expect(document.body.lastChild).toBeNull();
+ TestRenderer.act(() => {
+ testRenderer.update(
+
+ Test
+
+ );
+ });
+ expect(testRenderer!.toJSON()).toMatchSnapshot();
+ expect(document.body.lastElementChild!.getAttribute("data-portal")).toBe(
+ "modal"
+ );
+ TestRenderer.act(() => {
+ testRenderer.unmount();
+ });
+ expect(document.body.lastChild).toBeNull();
+});
+
+it("relays backdrop click events", () => {
+ const event = {};
+ const onBackdropClick = sinon.stub();
+ const onClose = sinon.stub();
+ expect(document.body.lastChild).toBeNull();
+ let testRenderer: ReactTestRenderer;
+ TestRenderer.act(() => {
+ testRenderer = TestRenderer.create(
+
+ Test
+ ,
+ { createNodeMock }
+ );
+ });
+ testRenderer!.root
+ .findByProps({ "data-testid": "backdrop" })
+ .props.onClick(event);
+ TestRenderer.act(() => {
+ testRenderer.unmount();
+ });
+ expect(onBackdropClick.called).toBe(true);
+ expect(onClose.calledWith(event, "backdropClick")).toBe(true);
+});
+
+it("relays esc events", () => {
+ const escEvent = { keyCode: 27 };
+ const otherEvent = { keyCode: 100 };
+ const onEscapeKeyDown = sinon.stub();
+ const onClose = sinon.stub();
+ expect(document.body.lastChild).toBeNull();
+ let testRenderer: ReactTestRenderer;
+ TestRenderer.act(() => {
+ testRenderer = TestRenderer.create(
+
+ Test
+ ,
+ { createNodeMock }
+ );
+ });
+ const el = testRenderer!.root.find(i => i.props.onKeyDown);
+ el.props.onKeyDown(escEvent);
+ el.props.onKeyDown(otherEvent);
+ TestRenderer.act(() => {
+ testRenderer.unmount();
+ });
+ expect(onEscapeKeyDown.called).toBe(true);
+ expect(onClose.calledWith(escEvent, "escapeKeyDown")).toBe(true);
+ expect(onClose.calledWith(otherEvent, "escapeKeyDown")).toBe(false);
+});
diff --git a/src/core/client/ui/components/v2/Modal/Modal.tsx b/src/core/client/ui/components/v2/Modal/Modal.tsx
new file mode 100644
index 000000000..c5f72184d
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/Modal.tsx
@@ -0,0 +1,132 @@
+import cn from "classnames";
+import React, {
+ FunctionComponent,
+ useCallback,
+ useEffect,
+ useState,
+} from "react";
+import ReactDOM from "react-dom";
+
+import { withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import Backdrop from "../Backdrop";
+import NoScroll from "../NoScroll";
+import TrapFocus from "../TrapFocus";
+
+import styles from "./Modal.css";
+
+function appendDivNode() {
+ const div = document.createElement("div");
+ document.body.append(div);
+ div.setAttribute("data-portal", "modal");
+ return div;
+}
+
+/**
+ * useDOMNode is a React hook that returns a DOM node
+ * to be used as a portal for the modal.
+ *
+ * @param open whether the modal is open or not.
+ */
+function useDOMNode(open: boolean) {
+ const [modalDOMNode, setModalDOMNode] = useState(null);
+ useEffect(() => {
+ if (open) {
+ const node = appendDivNode();
+ setModalDOMNode(node);
+ return () => {
+ node.parentElement!.removeChild(node);
+ setModalDOMNode(null);
+ };
+ }
+ return;
+ }, [open]);
+ return modalDOMNode;
+}
+
+export interface ModalProps {
+ onClose?: (
+ event: React.KeyboardEvent | React.MouseEvent,
+ reason: "backdropClick" | "escapeKeyDown"
+ ) => void;
+ onBackdropClick?: React.EventHandler;
+ onEscapeKeyDown?: React.EventHandler;
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ open?: boolean;
+ children?: PropTypesOf["children"];
+}
+
+const Modal: FunctionComponent = ({
+ classes,
+ open,
+ onClose,
+ className,
+ onBackdropClick,
+ onEscapeKeyDown,
+ children,
+ ...rest
+}) => {
+ const rootClassName = cn(classes.root, className);
+
+ const modalDOMNode = useDOMNode(Boolean(open));
+ const handleEscapeKeyDown = useCallback(
+ (e: React.KeyboardEvent) => {
+ if (e.keyCode === 27) {
+ if (onEscapeKeyDown) {
+ onEscapeKeyDown(e);
+ }
+ if (onClose) {
+ onClose(e, "escapeKeyDown");
+ }
+ }
+ },
+ [onEscapeKeyDown, onClose]
+ );
+ const handleBackdropClick = useCallback(
+ (e: React.MouseEvent) => {
+ if (onBackdropClick) {
+ onBackdropClick(e);
+ }
+ if (onClose) {
+ onClose(e, "backdropClick");
+ }
+ },
+ [onBackdropClick, onClose]
+ );
+
+ if (open && modalDOMNode) {
+ return ReactDOM.createPortal(
+ ,
+ modalDOMNode
+ );
+ }
+ return null;
+};
+
+const enhanced = withStyles(styles)(Modal);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Modal/__snapshots__/Modal.spec.tsx.snap b/src/core/client/ui/components/v2/Modal/__snapshots__/Modal.spec.tsx.snap
new file mode 100644
index 000000000..380445832
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/__snapshots__/Modal.spec.tsx.snap
@@ -0,0 +1,46 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
diff --git a/src/core/client/ui/components/v2/Modal/index.ts b/src/core/client/ui/components/v2/Modal/index.ts
new file mode 100644
index 000000000..2ddfc1688
--- /dev/null
+++ b/src/core/client/ui/components/v2/Modal/index.ts
@@ -0,0 +1 @@
+export { default, ModalProps } from "./Modal";
diff --git a/src/core/client/ui/components/v2/NoScroll/NoScroll.css b/src/core/client/ui/components/v2/NoScroll/NoScroll.css
new file mode 100644
index 000000000..7546b152d
--- /dev/null
+++ b/src/core/client/ui/components/v2/NoScroll/NoScroll.css
@@ -0,0 +1,3 @@
+.noScroll {
+ overflow: hidden;
+}
diff --git a/src/core/client/ui/components/v2/NoScroll/NoScroll.mdx b/src/core/client/ui/components/v2/NoScroll/NoScroll.mdx
new file mode 100644
index 000000000..6781badcb
--- /dev/null
+++ b/src/core/client/ui/components/v2/NoScroll/NoScroll.mdx
@@ -0,0 +1,35 @@
+---
+name: NoScroll
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import Container from "react-with-state-props";
+
+import Button from "../Button";
+import NoScroll from "./NoScroll";
+
+# NoScroll
+
+Disables scrolling of ``.
+
+## Basic usage
+
+
+ (
+
+
+ props.setValue(!props.value)}
+ >
+ Disable Scrolling
+
+
+ )}
+ />
+
diff --git a/src/core/client/ui/components/v2/NoScroll/NoScroll.spec.tsx b/src/core/client/ui/components/v2/NoScroll/NoScroll.spec.tsx
new file mode 100644
index 000000000..f5df1c4e8
--- /dev/null
+++ b/src/core/client/ui/components/v2/NoScroll/NoScroll.spec.tsx
@@ -0,0 +1,52 @@
+import React from "react";
+import TestRenderer, { ReactTestRenderer } from "react-test-renderer";
+
+import NoScroll from "./NoScroll";
+
+it("renders correctly", () => {
+ expect(document.body.className).toBe("");
+ let testRenderer: ReactTestRenderer;
+ TestRenderer.act(() => {
+ testRenderer = TestRenderer.create( );
+ });
+ expect(document.body.className).toBe("NoScroll-noScroll");
+ TestRenderer.act(() => {
+ testRenderer.update( );
+ });
+ expect(document.body.className).toBe("");
+});
+
+it("renders correctly with multiple instances", () => {
+ expect(document.body.className).toBe("");
+ let testRenderer: ReactTestRenderer;
+ TestRenderer.act(() => {
+ testRenderer = TestRenderer.create(
+ <>
+
+
+
+ >
+ );
+ });
+ expect(document.body.className).toBe("NoScroll-noScroll");
+ TestRenderer.act(() => {
+ testRenderer.update(
+ <>
+
+
+
+ >
+ );
+ });
+ expect(document.body.className).toBe("NoScroll-noScroll");
+ TestRenderer.act(() => {
+ testRenderer.update(
+ <>
+
+
+
+ >
+ );
+ });
+ expect(document.body.className).toBe("");
+});
diff --git a/src/core/client/ui/components/v2/NoScroll/NoScroll.tsx b/src/core/client/ui/components/v2/NoScroll/NoScroll.tsx
new file mode 100644
index 000000000..5e995f542
--- /dev/null
+++ b/src/core/client/ui/components/v2/NoScroll/NoScroll.tsx
@@ -0,0 +1,41 @@
+import { FunctionComponent, useEffect } from "react";
+
+import styles from "./NoScroll.css";
+
+interface Props {
+ /** If set to true, will disable scrolling on `` */
+ active?: boolean;
+}
+
+/** Counter of current instances */
+let instances = 0;
+
+const NoScroll: FunctionComponent = ({ active }) => {
+ useEffect(() => {
+ if (active) {
+ if (instances++ === 0) {
+ // Add className.
+ document.body.className = document.body.className
+ .split(/\s+/)
+ .filter(s => s)
+ .concat(styles.noScroll)
+ .join(" ");
+ }
+
+ // Cleanup hook.
+ return () => {
+ if (--instances === 0) {
+ // Remove className.
+ document.body.className = document.body.className
+ .split(/\s+/)
+ .filter(s => s && s !== styles.noScroll)
+ .join(" ");
+ }
+ };
+ }
+ return;
+ }, [active]);
+ return null;
+};
+
+export default NoScroll;
diff --git a/src/core/client/ui/components/v2/NoScroll/index.ts b/src/core/client/ui/components/v2/NoScroll/index.ts
new file mode 100644
index 000000000..71333faa8
--- /dev/null
+++ b/src/core/client/ui/components/v2/NoScroll/index.ts
@@ -0,0 +1 @@
+export { default } from "./NoScroll";
diff --git a/src/core/client/ui/components/v2/PasswordField/PasswordField.css b/src/core/client/ui/components/v2/PasswordField/PasswordField.css
new file mode 100644
index 000000000..5f874c3b2
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/PasswordField.css
@@ -0,0 +1,69 @@
+.root {
+ width: calc(29 * var(--mini-unit));
+ height: 36px;
+ line-height: 36px;
+ box-sizing: border-box;
+}
+
+.colorRegular {
+ background-color: var(--v2-palette-input-background);
+ color: var(--v2-palette-input-value);
+ border: 1px solid var(--v2-palette-input-border);
+}
+
+.colorError {
+ background-color: var(--v2-palette-input-background);
+ border-color: var(--v2-palette-error-main);
+ border: 2px solid var(--v2-palette-error-darkest);
+}
+
+.fullWidth {
+ width: 100%;
+}
+
+.wrapper {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+}
+
+.icon {
+ position: absolute;
+ display: inline-block;
+ right: 0px;
+ padding: 4px calc(1 * var(--mini-unit));
+ cursor: pointer;
+ line-height: 0;
+}
+
+.input {
+ font-family: var(--v2-font-family-primary);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-size: var(--v2-font-size-3);
+ line-height: var(--v2-line-height-reset);
+ display: block;
+ padding: var(--v2-spacing-2);
+ border-radius: var(--round-corners);
+ width: 100%;
+ height: 100%;
+ box-sizing: border-box;
+
+ &:read-only {
+ background-color: var(--v2-palette-input-disabled-background);
+ }
+ &:disabled {
+ background-color: var(--v2-palette-input-disabled-background);
+ border-color: var(--v2-palette-input-disabled-foreground);
+ }
+ &:focus {
+ outline: none;
+ border: 1px solid var(--v2-palette-input-focused-border);
+ box-shadow: inset 0px 0px 0px 1px var(--v2-palette-input-focused-border);
+ }
+ &::placeholder {
+ color: var(--v2-palette-input-placeholder);
+ }
+}
diff --git a/src/core/client/ui/components/v2/PasswordField/PasswordField.mdx b/src/core/client/ui/components/v2/PasswordField/PasswordField.mdx
new file mode 100644
index 000000000..965d2dd97
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/PasswordField.mdx
@@ -0,0 +1,25 @@
+---
+name: PasswordField
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from "docz";
+import PasswordField from "./PasswordField.tsx";
+import HorizontalGutter from "../HorizontalGutter";
+
+# PasswordField
+
+## Basic Use
+
+
+
+
+
+
+
+
+
diff --git a/src/core/client/ui/components/v2/PasswordField/PasswordField.spec.tsx b/src/core/client/ui/components/v2/PasswordField/PasswordField.spec.tsx
new file mode 100644
index 000000000..a5e4618f5
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/PasswordField.spec.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import PasswordField from "./PasswordField";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ defaultValue: "Hello World",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+
+ renderer.root.findByProps({ role: "button" }).props.onClick();
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/PasswordField/PasswordField.tsx b/src/core/client/ui/components/v2/PasswordField/PasswordField.tsx
new file mode 100644
index 000000000..f9772114c
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/PasswordField.tsx
@@ -0,0 +1,162 @@
+import cn from "classnames";
+import React, {
+ AllHTMLAttributes,
+ ChangeEvent,
+ Component,
+ EventHandler,
+ KeyboardEvent,
+} from "react";
+
+import { withStyles } from "coral-ui/hocs";
+
+import Icon from "coral-ui/components/Icon";
+
+import styles from "./PasswordField.css";
+
+export interface PasswordFieldProps {
+ id?: string;
+ /**
+ * The content value of the component.
+ */
+ defaultValue?: string;
+ /**
+ * The content value of the component.
+ */
+ value?: string;
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /**
+ * Color of the PasswordField
+ */
+ color?: "regular" | "error";
+ /*
+ * If set renders a full width button
+ */
+ fullWidth?: boolean;
+ /**
+ * Placeholder
+ */
+ placeholder?: string;
+ /**
+ * Mark as readonly
+ */
+ readOnly?: boolean;
+ /**
+ * Name
+ */
+ name?: string;
+ /**
+ * onChange
+ */
+ onChange?: EventHandler>;
+
+ disabled?: boolean;
+
+ autoComplete?: AllHTMLAttributes["autoComplete"];
+ autoCorrect?: AllHTMLAttributes["autoCorrect"];
+ autoCapitalize?: AllHTMLAttributes["autoCapitalize"];
+ spellCheck?: AllHTMLAttributes["spellCheck"];
+
+ showPasswordTitle?: string;
+ hidePasswordTitle?: string;
+}
+
+interface State {
+ reveal: boolean;
+}
+
+class PasswordField extends Component {
+ public static defaultProps: Partial = {
+ color: "regular",
+ placeholder: "",
+ showPasswordTitle: "Hide password",
+ hidePasswordTitle: "Show password",
+ autoCapitalize: "off",
+ autoCorrect: "off",
+ autoComplete: "off",
+ spellCheck: false,
+ };
+
+ public state = {
+ reveal: false,
+ };
+
+ private handleVisibilityKeyUp = (e: KeyboardEvent) => {
+ // Number 13 is the "Enter" key on the keyboard
+ if (e.keyCode === 13) {
+ this.toggleVisibility();
+ }
+ };
+
+ private toggleVisibility = () => {
+ this.setState(state => ({
+ reveal: !state.reveal,
+ }));
+ };
+
+ public render() {
+ const {
+ className,
+ classes,
+ color,
+ fullWidth,
+ value,
+ placeholder,
+ hidePasswordTitle,
+ showPasswordTitle,
+ ...rest
+ } = this.props;
+
+ const rootClassName = cn(
+ {
+ [classes.fullWidth]: fullWidth,
+ },
+ classes.root,
+ className
+ );
+
+ const inputClassName = cn(
+ {
+ [classes.colorRegular]: color === "regular",
+ [classes.colorError]: color === "error",
+ [classes.fullWidth]: fullWidth,
+ },
+ classes.input
+ );
+
+ const reveal = this.state.reveal;
+
+ return (
+
+
+
+
+ {reveal ? "visibility_off" : "visibility"}
+
+
+
+ );
+ }
+}
+
+const enhanced = withStyles(styles)(PasswordField);
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/PasswordField/__snapshots__/PasswordField.spec.tsx.snap b/src/core/client/ui/components/v2/PasswordField/__snapshots__/PasswordField.spec.tsx.snap
new file mode 100644
index 000000000..0a900db11
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/__snapshots__/PasswordField.spec.tsx.snap
@@ -0,0 +1,73 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+`;
+
+exports[`renders correctly 2`] = `
+
+
+
+
+
+ visibility_off
+
+
+
+
+`;
diff --git a/src/core/client/ui/components/v2/PasswordField/index.ts b/src/core/client/ui/components/v2/PasswordField/index.ts
new file mode 100644
index 000000000..7cb96a599
--- /dev/null
+++ b/src/core/client/ui/components/v2/PasswordField/index.ts
@@ -0,0 +1,2 @@
+export * from "./PasswordField";
+export { default } from "./PasswordField";
diff --git a/src/core/client/ui/components/v2/Popover/Arrow.css b/src/core/client/ui/components/v2/Popover/Arrow.css
new file mode 100644
index 000000000..ba6cd14c1
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/Arrow.css
@@ -0,0 +1,142 @@
+.root {
+ position: absolute;
+ width: 20px;
+ height: 20px;
+
+ &[data-placement*="bottom"] {
+ top: 0;
+ left: 0;
+ margin-top: -6px;
+ width: 20px;
+ height: 6px;
+ filter: drop-shadow(0px -2px 1px rgba(0, 0, 0, 0.1));
+ &::before {
+ border-width: 0 10px 6px 10px;
+ border-color: transparent transparent var(--v2-palette-popover-border)
+ transparent;
+ }
+ &::after {
+ margin-top: -5px;
+ border-width: 0 10px 6px 10px;
+ border-color: transparent transparent var(--v2-palette-popover-background)
+ transparent;
+ }
+ &.colorDark {
+ &::before {
+ border-color: transparent transparent var(--v2-palette-popover-dark-border)
+ transparent;
+ }
+ &::after {
+ border-color: transparent transparent var(--v2-palette-popover-dark-border)
+ transparent;
+ }
+ }
+ }
+
+ &[data-placement*="top"] {
+ bottom: 0;
+ left: 0;
+ margin-bottom: -6px;
+ width: 20px;
+ height: 6px;
+ filter: drop-shadow(0px 2px 1px rgba(0, 0, 0, 0.1));
+ &::before {
+ border-width: 6px 10px 0 10px;
+ border-color: var(--v2-palette-popover-border) transparent transparent
+ transparent;
+ }
+ &::after {
+ margin-top: -7px;
+ border-width: 6px 10px 0 10px;
+ border-color: var(--v2-palette-popover-background) transparent transparent
+ transparent;
+ }
+ &.colorDark {
+ &::before {
+ border-color: var(--v2-palette-popover-dark-border) transparent transparent
+ transparent;
+ }
+ &::after {
+ border-color: var(--v2-palette-popover-dark-border) transparent transparent
+ transparent;
+ }
+ }
+ }
+
+ &[data-placement*="right"] {
+ left: 0;
+ height: 20px;
+ width: 6px;
+ margin-left: -6px;
+ filter: drop-shadow(-1px 0px 1px rgba(0, 0, 0, 0.1));
+ &::before {
+ border-width: 10px 6px 10px 0;
+ border-color: transparent var(--v2-palette-popover-border) transparent
+ transparent;
+ }
+ &::after {
+ margin-top: -20px;
+ margin-right: -1px;
+ border-width: 10px 6px 10px 0;
+ border-color: transparent var(--v2-palette-popover-background) transparent
+ transparent;
+ }
+ &.colorDark {
+ &::before {
+ border-color: transparent var(--v2-palette-popover-dark-border) transparent
+ transparent;
+ }
+ &::after {
+ border-color: transparent var(--v2-palette-popover-dark-border) transparent
+ transparent;
+ }
+ }
+ }
+
+ &[data-placement*="left"] {
+ right: 0;
+ height: 20px;
+ width: 6px;
+ margin-right: -6px;
+ filter: drop-shadow(1px 0px 1px rgba(0, 0, 0, 0.1));
+ &::before {
+ border-width: 10px 0 10px 6px;
+ border-color: transparent transparent transparent
+ var(--v2-palette-popover-border);
+ }
+ &::after {
+ margin-top: -20px;
+ margin-left: -1px;
+ border-width: 10px 0 10px 6px;
+ border-color: transparent transparent transparent
+ var(--v2-palette-popover-background);
+ }
+ &.colorDark {
+ &::before {
+ border-color: transparent transparent transparent
+ var(--v2-palette-popover-dark-border);
+ }
+ &::after {
+ border-color: transparent transparent transparent
+ var(--v2-palette-popover-dark-border);
+ }
+ }
+ }
+
+ &::before {
+ content: "";
+ margin: auto;
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ }
+ &::after {
+ content: "";
+ margin: auto;
+ display: block;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ }
+}
diff --git a/src/core/client/ui/components/v2/Popover/Arrow.tsx b/src/core/client/ui/components/v2/Popover/Arrow.tsx
new file mode 100644
index 000000000..e40145a6a
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/Arrow.tsx
@@ -0,0 +1,26 @@
+import cn from "classnames";
+import React, { FunctionComponent, Ref } from "react";
+
+import { withForwardRef } from "coral-ui/hocs";
+
+import styles from "./Arrow.css";
+
+interface Props extends React.HTMLAttributes {
+ dark?: boolean;
+ forwardRef?: Ref;
+}
+
+const Arrow: FunctionComponent = props => {
+ const { className, dark, forwardRef: ref, ...rest } = props;
+ return (
+
+ );
+};
+
+export default withForwardRef(Arrow);
diff --git a/src/core/client/ui/components/v2/Popover/Popover.css b/src/core/client/ui/components/v2/Popover/Popover.css
new file mode 100644
index 000000000..3b55e6491
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/Popover.css
@@ -0,0 +1,30 @@
+.root {
+}
+
+.popover {
+ background: var(--v2-palette-popover-background);
+ border: 1px solid var(--v2-palette-popover-border);
+ box-sizing: border-box;
+ box-shadow: var(--elevation-main);
+ border-radius: var(--round-corners);
+ z-index: var(--zindex-popover);
+ margin: 2px;
+}
+
+.colorDark {
+ background: var(--v2-palette-popover-dark-background);
+ border-color: var(--v2-palette-popover-dark-border);
+}
+
+.top {
+ margin: calc(0.5 * var(--mini-unit)) 0;
+}
+.left {
+ margin: 0 calc(0.5 * var(--mini-unit));
+}
+.right {
+ margin: 0 calc(0.5 * var(--mini-unit));
+}
+.bottom {
+ margin: calc(0.5 * var(--mini-unit)) 0;
+}
diff --git a/src/core/client/ui/components/v2/Popover/Popover.mdx b/src/core/client/ui/components/v2/Popover/Popover.mdx
new file mode 100644
index 000000000..54434116b
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/Popover.mdx
@@ -0,0 +1,88 @@
+---
+name: Popover
+menu: UI Kit
+---
+
+import { Playground } from "docz";
+import Popover from "./Popover";
+import Button from "../Button";
+import Flex from "../Flex";
+import Typography from "../Typography";
+import ButtonIcon from "../Button/ButtonIcon";
+import BaseButton from "../BaseButton";
+import ClickOutside from "../ClickOutside";
+import Icon from "../Icon";
+
+# Popover
+
+`Popover` renders a popover dialog attached to another `Element`.
+
+## Basic usage
+
+
+ This is the body }
+ >
+ {({ toggleVisibility, ref }) => (
+
+ Click me!
+
+ )}
+
+
+
+#### Example with `placement=top`
+
+
+ (
+
+ This is the body
+
+ close
+
+
+ )}
+ >
+ {({ toggleVisibility, ref }) => (
+
+ Click me!
+
+ )}
+
+
+
+## Tooltip
+
+
+ (
+
+
+ I am a Tooltip
+
+
+ )}
+ dark
+ >
+ {({ toggleVisibility, ref }) => (
+
+ info
+
+ )}
+
+
diff --git a/src/core/client/ui/components/v2/Popover/Popover.tsx b/src/core/client/ui/components/v2/Popover/Popover.tsx
new file mode 100644
index 000000000..af6cb4c31
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/Popover.tsx
@@ -0,0 +1,202 @@
+import cn from "classnames";
+import React from "react";
+import { Manager, Popper, Reference, RefHandler } from "react-popper";
+
+import { oncePerFrame } from "coral-common/utils";
+import { withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import { AriaInfo } from "coral-ui/components";
+
+import Arrow from "./Arrow";
+import styles from "./Popover.css";
+
+type Placement =
+ | "top-start"
+ | "top"
+ | "top-end"
+ | "right-start"
+ | "right"
+ | "right-end"
+ | "bottom-end"
+ | "bottom"
+ | "bottom-start"
+ | "left-end"
+ | "left"
+ | "left-start";
+
+interface BodyRenderProps {
+ /** toggles visibility, if event is provided, the event will stop propagating. */
+ toggleVisibility: (event?: React.SyntheticEvent | Event) => void;
+ visible: boolean;
+ scheduleUpdate: () => void;
+}
+
+interface ChildrenRenderProps {
+ /** toggles visibility, if event is provided, the event will stop propagating. */
+ toggleVisibility: (event?: React.SyntheticEvent | Event) => void;
+ ref?: RefHandler;
+ visible: boolean;
+}
+
+interface PopoverProps {
+ body: (props: BodyRenderProps) => React.ReactNode | React.ReactElement;
+ children: (props: ChildrenRenderProps) => React.ReactNode;
+ description?: string;
+ id: string;
+ className?: string;
+ placement?: Placement;
+ visible?: boolean;
+ classes: typeof styles;
+ modifiers?: PropTypesOf["modifiers"];
+ eventsEnabled?: PropTypesOf["eventsEnabled"];
+ positionFixed?: PropTypesOf["positionFixed"];
+ dark?: boolean;
+}
+
+interface State {
+ visible: boolean;
+}
+
+class Popover extends React.Component {
+ public static defaultProps: Partial = {
+ placement: "top",
+ };
+ public state: State = {
+ visible: false,
+ };
+
+ private toggleVisibility = (() => {
+ let fn = (event?: React.SyntheticEvent | Event) => {
+ this.setState((state: State) => ({
+ visible: !state.visible,
+ }));
+ };
+ if (process.env.NODE_ENV !== "test") {
+ /**
+ * Only run this once per frame in the browser, otherwise
+ * we might get into a situation where this is called twice
+ * by different event handlers cancelling each other out.
+ *
+ * We don't wan this behavior when running in a simulated browser
+ * environment with simulated events.
+ */
+ fn = oncePerFrame(fn);
+ }
+ return fn;
+ })();
+
+ private close = () => {
+ this.setState((state: State) => ({
+ visible: false,
+ }));
+ };
+
+ private handleEsc = (e: KeyboardEvent) => {
+ if (e.key === "Escape") {
+ e.preventDefault();
+ this.close();
+ }
+ };
+
+ public componentDidMount() {
+ document.addEventListener("keydown", this.handleEsc, true);
+ }
+
+ public componentWillUnmount() {
+ document.removeEventListener("keydown", this.handleEsc, true);
+ }
+
+ public render() {
+ const {
+ id,
+ body,
+ children,
+ description,
+ className,
+ placement,
+ classes,
+ visible: controlledVisible,
+ positionFixed,
+ modifiers,
+ eventsEnabled,
+ dark,
+ ...rest
+ } = this.props;
+
+ const visible =
+ controlledVisible !== undefined ? controlledVisible : this.state.visible;
+ const includeArrow =
+ !modifiers || !modifiers.arrow || modifiers.arrow.enabled;
+ const popoverClassName = cn(classes.popover, {
+ [classes.top]: placement!.startsWith("top"),
+ [classes.left]: placement!.startsWith("left"),
+ [classes.right]: placement!.startsWith("right"),
+ [classes.bottom]: placement!.startsWith("bottom"),
+ });
+
+ return (
+
+
+
+ {props =>
+ children({
+ ref: props.ref,
+ toggleVisibility: this.toggleVisibility,
+ visible,
+ })
+ }
+
+
+ {props => (
+
+ {description && (
+
{description}
+ )}
+ {visible && (
+
+ {includeArrow && (
+
+ )}
+ {typeof body === "function"
+ ? body({
+ scheduleUpdate: props.scheduleUpdate,
+ toggleVisibility: this.toggleVisibility,
+ visible,
+ })
+ : body}
+
+ )}
+
+ )}
+
+
+
+ );
+ }
+}
+
+const enhanced = withStyles(styles)(Popover);
+
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/Popover/index.ts b/src/core/client/ui/components/v2/Popover/index.ts
new file mode 100644
index 000000000..04072ed30
--- /dev/null
+++ b/src/core/client/ui/components/v2/Popover/index.ts
@@ -0,0 +1 @@
+export { default } from "./Popover";
diff --git a/src/core/client/ui/components/v2/RadioButton/RadioButton.css b/src/core/client/ui/components/v2/RadioButton/RadioButton.css
new file mode 100644
index 000000000..359089cdd
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/RadioButton.css
@@ -0,0 +1,80 @@
+.root {
+}
+
+.input {
+ cursor: pointer;
+ position: absolute; /* take it out of document flow */
+ opacity: 0; /* hide it */
+}
+
+.label {
+ display: flex;
+ position: relative;
+ cursor: pointer;
+ user-select: none;
+ color: var(--v2-palette-input-label);
+ font-size: var(--v2-font-size-3);
+ font-weight: var(--v2-font-weight-primary-regular);
+ font-family: var(--v2-font-family-primary);
+ line-height: var(--v2-line-height-body-short);
+ align-items: center;
+}
+
+.labelLight {
+ color: var(--palette-text-light);
+}
+
+/* Box. */
+.input + .label:before {
+ content: "";
+ margin-right: 10px;
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ background: var(--v2-palette-input-background);
+ border: 1px solid var(--v2-palette-input-label);
+ border-radius: 50%;
+ box-sizing: border-box;
+ flex-shrink: 0;
+}
+
+/* Box focus */
+.label.focus:before {
+ @mixin outline;
+}
+
+/* Box checked */
+.input:checked + .label:before {
+ border: 1px solid var(--v2-palette-input-label);
+ background: var(--v2-palette-input-background);
+}
+
+/* Disabled state label. */
+.input:disabled + .label {
+ cursor: auto;
+ opacity: 0.6;
+}
+
+/* Disabled box. */
+.input:disabled + .label:before {
+ box-shadow: none;
+ border: 1px solid var(--v2-palette-input-disabled-foreground);
+ background: var(--v2-palette-input-disabled-background);
+}
+
+/* Checkmark. Could be replaced with an image */
+.input:checked + .label:after {
+ content: "";
+ background: var(--v2-palette-input-label);
+ border-radius: 50%;
+ position: absolute;
+ left: 3px;
+ top: 6px;
+ width: 8px;
+ height: 8px;
+ box-sizing: border-box;
+}
+
+.input:checked:disabled + .label:after {
+ background: var(--v2-palette-input-disabled-background);
+}
diff --git a/src/core/client/ui/components/v2/RadioButton/RadioButton.mdx b/src/core/client/ui/components/v2/RadioButton/RadioButton.mdx
new file mode 100644
index 000000000..20377f4bc
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/RadioButton.mdx
@@ -0,0 +1,20 @@
+---
+name: RadioButton
+menu: UI Kit
+---
+
+import { Playground, PropsTable } from 'docz'
+import RadioButton from './RadioButton.tsx'
+import HorizontalGutter from '../HorizontalGutter'
+
+# RadioButton
+
+## Basic Use
+
+
+ Yes I agree
+ I don't agree
+ Disabled
+ Disabled + Checked
+
+
diff --git a/src/core/client/ui/components/v2/RadioButton/RadioButton.spec.tsx b/src/core/client/ui/components/v2/RadioButton/RadioButton.spec.tsx
new file mode 100644
index 000000000..30958d6a7
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/RadioButton.spec.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import RadioButton from "./RadioButton";
+
+it("renders correctly", () => {
+ const props: PropTypesOf = {
+ className: "custom",
+ id: "radioID",
+ name: "key",
+ value: "true",
+ children: "Yes I agree",
+ };
+ const renderer = TestRenderer.create( );
+ expect(renderer.toJSON()).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/RadioButton/RadioButton.tsx b/src/core/client/ui/components/v2/RadioButton/RadioButton.tsx
new file mode 100644
index 000000000..d725cdf77
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/RadioButton.tsx
@@ -0,0 +1,89 @@
+import cn from "classnames";
+import React, { ChangeEvent, Component, EventHandler, FocusEvent } from "react";
+import uuid from "uuid/v4";
+
+import { Flex } from "coral-ui/components";
+import { withKeyboardFocus, withStyles } from "coral-ui/hocs";
+
+import styles from "./RadioButton.css";
+
+export interface RadioButtonProps {
+ id?: string;
+ /**
+ * The content value of the component.
+ */
+ value?: string;
+
+ checked?: boolean;
+
+ /**
+ * Convenient prop to override the root styling.
+ */
+ className?: string;
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: typeof styles;
+ /**
+ * Mark as readonly
+ */
+ readOnly?: boolean;
+ /**
+ * Name
+ */
+ name?: string;
+ /**
+ * onChange
+ */
+ onChange?: EventHandler>;
+
+ disabled?: boolean;
+ children: React.ReactNode;
+ /**
+ * Display a light text.
+ */
+ light?: boolean;
+
+ // These handlers are passed down by the `withKeyboardFocus` HOC.
+ onFocus: EventHandler>;
+ onBlur: EventHandler>;
+ keyboardFocus: boolean;
+}
+
+class RadioButton extends Component {
+ public state = {
+ randomID: uuid(),
+ };
+ public render() {
+ const {
+ className,
+ classes,
+ id,
+ light,
+ children,
+ keyboardFocus,
+ ...rest
+ } = this.props;
+
+ const rootClassName = cn(classes.root, className);
+ const finalID = id || this.state.randomID;
+
+ return (
+
+
+
+ {children}
+
+
+ );
+ }
+}
+
+const enhanced = withStyles(styles)(withKeyboardFocus(RadioButton));
+export default enhanced;
diff --git a/src/core/client/ui/components/v2/RadioButton/__snapshots__/RadioButton.spec.tsx.snap b/src/core/client/ui/components/v2/RadioButton/__snapshots__/RadioButton.spec.tsx.snap
new file mode 100644
index 000000000..f8dad0dcc
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/__snapshots__/RadioButton.spec.tsx.snap
@@ -0,0 +1,23 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+
+
+
+ Yes I agree
+
+
+`;
diff --git a/src/core/client/ui/components/v2/RadioButton/index.ts b/src/core/client/ui/components/v2/RadioButton/index.ts
new file mode 100644
index 000000000..ed12488fa
--- /dev/null
+++ b/src/core/client/ui/components/v2/RadioButton/index.ts
@@ -0,0 +1,2 @@
+export * from "./RadioButton";
+export { default } from "./RadioButton";
diff --git a/src/core/client/ui/components/v2/RelativeTime/RelativeTime.css b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.css
new file mode 100644
index 000000000..c3a2af639
--- /dev/null
+++ b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.css
@@ -0,0 +1,2 @@
+.root {
+}
diff --git a/src/core/client/ui/components/v2/RelativeTime/RelativeTime.mdx b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.mdx
new file mode 100644
index 000000000..3122e8806
--- /dev/null
+++ b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.mdx
@@ -0,0 +1,17 @@
+---
+name: RelativeTime
+menu: UI Kit
+---
+
+import { Playground } from 'docz'
+import RelativeTime from './RelativeTime'
+
+# RelativeTime
+
+Renders relative time until given `date`.
+
+## Basic usage
+
+ "".concat(value, " ", unit, " ", suffix)} />
+
diff --git a/src/core/client/ui/components/v2/RelativeTime/RelativeTime.spec.tsx b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.spec.tsx
new file mode 100644
index 000000000..fe56898d3
--- /dev/null
+++ b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.spec.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import { create } from "react-test-renderer";
+
+import { PropTypesOf } from "coral-ui/types";
+
+import UIContext from "../UIContext";
+import RelativeTime from "./RelativeTime";
+
+it("uses default formatter", () => {
+ const props = {
+ date: "2018-12-17T03:24:00.000Z",
+ };
+ const tree = create( ).toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
+
+it("uses formatter from context", () => {
+ const context: any = {
+ timeagoFormatter: () => "My Context Formatter",
+ };
+ const props: PropTypesOf = {
+ date: "2018-12-17T03:24:00.000Z",
+ };
+ const tree = create(
+
+
+
+ ).toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
+
+it("uses formatter from props", () => {
+ const props = {
+ date: "2018-12-17T03:24:00.000Z",
+ formatter: () => "My Props Formatter",
+ };
+ const tree = create( ).toJSON();
+
+ expect(tree).toMatchSnapshot();
+});
diff --git a/src/core/client/ui/components/v2/RelativeTime/RelativeTime.tsx b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.tsx
new file mode 100644
index 000000000..8f203cdb5
--- /dev/null
+++ b/src/core/client/ui/components/v2/RelativeTime/RelativeTime.tsx
@@ -0,0 +1,43 @@
+import cn from "classnames";
+import React, { Ref } from "react";
+import TimeAgo, { Formatter } from "react-timeago";
+
+import { UIContext } from "coral-ui/components/v2";
+import { withForwardRef, withStyles } from "coral-ui/hocs";
+import { PropTypesOf } from "coral-ui/types";
+
+import styles from "./RelativeTime.css";
+
+interface Props {
+ date: string;
+ live?: boolean;
+ classes: typeof styles;
+ className?: string;
+ formatter?: Formatter;
+
+ /** Internal: Forwarded Ref */
+ forwardRef?: Ref;
+}
+
+const defaultFormatter: Formatter = (value, unit, suffix, timestamp: string) =>
+ new Date(timestamp).toISOString();
+
+const RelativeTime: React.FunctionComponent = props => {
+ const { date, classes, live, className, formatter } = props;
+ return (
+