diff --git a/package.json b/package.json index 13e577a0..263c077b 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "@react-navigation/native": "^5.9.3", "@react-navigation/stack": "^5.14.3", "@standardnotes/sncrypto-common": "1.7.0", - "@standardnotes/snjs": "2.61.0", - "@standardnotes/stylekit": "5.5.0", + "@standardnotes/snjs": "2.63.1", + "@standardnotes/stylekit": "5.9.0", "js-base64": "^3.5.2", "moment": "^2.29.1", "react": "17.0.2", @@ -69,8 +69,8 @@ "@babel/core": "^7.11.6", "@babel/runtime": "^7.11.2", "@react-native-community/eslint-config": "^2.0.0", - "@standardnotes/components": "^1.7.3", - "@standardnotes/features": "^1.32.6", + "@standardnotes/components": "^1.7.5", + "@standardnotes/features": "^1.32.11", "@types/detox": "^16.4.1", "@types/faker": "^5.1.3", "@types/jest": "^26.0.14", diff --git a/src/components/SnIcon.tsx b/src/components/SnIcon.tsx index 25d44ef7..32e13328 100644 --- a/src/components/SnIcon.tsx +++ b/src/components/SnIcon.tsx @@ -4,6 +4,8 @@ import ArchiveIcon from '@standardnotes/stylekit/dist/icons/ic-archive.svg'; import AuthenticatorIcon from '@standardnotes/stylekit/dist/icons/ic-authenticator.svg'; import CodeIcon from '@standardnotes/stylekit/dist/icons/ic-code.svg'; import MarkdownIcon from '@standardnotes/stylekit/dist/icons/ic-markdown.svg'; +import NotesIcon from '@standardnotes/stylekit/dist/icons/ic-notes.svg'; +import OpenInIcon from '@standardnotes/stylekit/dist/icons/ic-open-in.svg'; import PencilOffIcon from '@standardnotes/stylekit/dist/icons/ic-pencil-off.svg'; import PinFilledIcon from '@standardnotes/stylekit/dist/icons/ic-pin-filled.svg'; import SpreadsheetsIcon from '@standardnotes/stylekit/dist/icons/ic-spreadsheets.svg'; @@ -11,6 +13,7 @@ import TasksIcon from '@standardnotes/stylekit/dist/icons/ic-tasks.svg'; import PlainTextIcon from '@standardnotes/stylekit/dist/icons/ic-text-paragraph.svg'; import RichTextIcon from '@standardnotes/stylekit/dist/icons/ic-text-rich.svg'; import TrashFilledIcon from '@standardnotes/stylekit/dist/icons/ic-trash-filled.svg'; +import UserAddIcon from '@standardnotes/stylekit/dist/icons/ic-user-add.svg'; import React, { useContext } from 'react'; import { ThemeContext } from 'styled-components'; @@ -26,6 +29,9 @@ const ICONS = { 'trash-filled': TrashFilledIcon, 'pin-filled': PinFilledIcon, archive: ArchiveIcon, + 'user-add': UserAddIcon, + 'open-in': OpenInIcon, + notes: NotesIcon, }; export type TEditorIcon = Extract< @@ -42,9 +48,10 @@ export type TEditorIcon = Extract< | 'pin-filled' | 'archive' >; +export type TGeneralIcon = Extract; type Props = { - type: TEditorIcon; + type: TEditorIcon | TGeneralIcon; fill?: string; styles?: Record; }; diff --git a/src/lib/interface.ts b/src/lib/interface.ts index 7d20717a..918b42df 100644 --- a/src/lib/interface.ts +++ b/src/lib/interface.ts @@ -1,5 +1,5 @@ import AsyncStorage from '@react-native-community/async-storage'; -import { ApplicationIdentifier, DeviceInterface } from '@standardnotes/snjs'; +import { ApplicationIdentifier, AbstractDevice } from '@standardnotes/snjs'; import { Alert, Linking, Platform } from 'react-native'; import DefaultPreference from 'react-native-default-preference'; import FingerprintScanner from 'react-native-fingerprint-scanner'; @@ -45,7 +45,7 @@ const showLoadFailForItemIds = (failedItemIds: string[]) => { Alert.alert('Unable to load item(s)', text); }; -export class MobileDeviceInterface extends DeviceInterface { +export class MobileDeviceInterface extends AbstractDevice { constructor() { super(setTimeout, setInterval); } diff --git a/src/screens/SideMenu/Listed.styled.ts b/src/screens/SideMenu/Listed.styled.ts new file mode 100644 index 00000000..d63c54d7 --- /dev/null +++ b/src/screens/SideMenu/Listed.styled.ts @@ -0,0 +1,35 @@ +import { StyleSheet } from 'react-native'; +import styled from 'styled-components/native'; + +export const styles = StyleSheet.create({ + blogItemIcon: { + marginTop: -6, + }, + loadingIndicator: { + alignSelf: 'flex-start', + }, + blogActionInProgressIndicator: { + marginTop: -5, + marginLeft: 6, + transform: [ + { + scale: 0.8, + }, + ], + }, +}); +export const CreateBlogContainer = styled.View` + margin-bottom: 8px; +`; +export const CantLoadActionsText = styled.Text` + font-size: 12px; + margin-top: -12px; + margin-bottom: 10px; + opacity: 0.7; + color: ${({ theme }) => theme.stylekitContrastForegroundColor}; +`; +export const ListedItemRow = styled.View` + display: flex; + flex-direction: row; + align-items: center; +`; diff --git a/src/screens/SideMenu/Listed.tsx b/src/screens/SideMenu/Listed.tsx new file mode 100644 index 00000000..ef86ea0c --- /dev/null +++ b/src/screens/SideMenu/Listed.tsx @@ -0,0 +1,242 @@ +import { SnIcon } from '@Components/SnIcon'; +import { ApplicationContext } from '@Root/ApplicationContext'; +import { + CantLoadActionsText, + CreateBlogContainer, + ListedItemRow, + styles, +} from '@Screens/SideMenu/Listed.styled'; +import { SideMenuCell } from '@Screens/SideMenu/SideMenuCell'; +import { SideMenuOptionIconDescriptionType } from '@Screens/SideMenu/SideMenuSection'; +import { ButtonType, ListedAccount, SNNote } from '@standardnotes/snjs'; +import { ListedAccountInfo } from '@standardnotes/snjs/dist/@types/services/api/responses'; +import { useCustomActionSheet } from '@Style/custom_action_sheet'; +import React, { FC, useCallback, useContext, useEffect, useState } from 'react'; +import { ActivityIndicator, FlatList, View } from 'react-native'; + +type TProps = { + note: SNNote; +}; + +type TListedAccountItem = + | ListedAccountInfo + | Pick; + +export const Listed: FC = ({ note }) => { + const application = useContext(ApplicationContext); + + const [isLoading, setIsLoading] = useState(false); + const [isActionInProgress, setIsActionInProgress] = useState(false); + const [isRequestingAccount, setIsRequestingAccount] = useState(false); + + const [listedAccounts, setListedAccounts] = useState([]); + const [listedAccountDetails, setListedAccountDetails] = useState< + TListedAccountItem[] + >([]); + const [ + authorUrlWithInProgressAction, + setAuthorUrlWithInProgressAction, + ] = useState(null); + + const { showActionSheet } = useCustomActionSheet(); + + const getListedAccountsDetails = useCallback( + async (accounts: ListedAccount[]) => { + if (!application) { + return; + } + const listedAccountsArray: TListedAccountItem[] = []; + + for (const listedAccountItem of accounts) { + const listedItemInfo = await application.getListedAccountInfo( + listedAccountItem, + note?.uuid + ); + + listedAccountsArray.push( + listedItemInfo + ? listedItemInfo + : { display_name: listedAccountItem.authorId } + ); + } + return listedAccountsArray; + }, + [application, note?.uuid] + ); + + const reloadListedAccounts = useCallback(async () => { + if (!application) { + return []; + } + setIsLoading(true); + const accounts = await application.getListedAccounts(); + setListedAccounts(accounts); + + setListedAccountDetails((await getListedAccountsDetails(accounts)) || []); + setIsLoading(false); + }, [application, getListedAccountsDetails]); + + const registerNewAccount = useCallback(() => { + if (!application || isRequestingAccount) { + return; + } + + const requestAccount = async () => { + setIsRequestingAccount(true); + const account = await application.requestNewListedAccount(); + if (account) { + const openSettings = await application.alertService.confirm( + 'Your new Listed blog has been successfully created!' + + ' You can publish a new post to your blog from Standard Notes via the' + + ' Actions menu in the editor pane. Open your blog settings to begin setting it up.', + undefined, + 'Open Settings', + ButtonType.Info, + 'Later' + ); + reloadListedAccounts(); + + if (openSettings) { + const info = await application.getListedAccountInfo(account); + if (info) { + application.deviceInterface.openUrl(info?.settings_url); + } + } + } + setIsRequestingAccount(false); + }; + + requestAccount(); + }, [application, isRequestingAccount, reloadListedAccounts]); + + useEffect(() => { + const loadListedData = async () => { + await reloadListedAccounts(); + }; + loadListedData(); + }, [reloadListedAccounts]); + + const doesListedItemHaveActions = ( + item: TListedAccountItem + ): item is ListedAccountInfo => { + return (item as ListedAccountInfo).author_url !== undefined; + }; + + const showActionsMenu = (item: TListedAccountItem, index: number) => { + if (!application) { + return; + } + if (!doesListedItemHaveActions(item)) { + application.alertService.alert('Unable to load actions.'); + return; + } + showActionSheet( + item.display_name, + item.actions.map(action => ({ + text: action.label, + callback: async () => { + setIsActionInProgress(true); + setAuthorUrlWithInProgressAction(item.author_url); + + const response = await application.actionsManager.runAction( + action, + note + ); + + if (!response || response.error) { + setIsActionInProgress(false); + setAuthorUrlWithInProgressAction(null); + return; + } + const listedDetails = (await getListedAccountsDetails( + listedAccounts + )) as TListedAccountItem[]; + setListedAccountDetails(listedDetails); + + showActionsMenu(listedDetails[index], index); + setIsActionInProgress(false); + setAuthorUrlWithInProgressAction(null); + }, + })) + ); + }; + + if (!application) { + return null; + } + return ( + + {isLoading && } + {listedAccountDetails.length > 0 && ( + { + if (!item) { + return null; + } + return ( + + + showActionsMenu(item, index)} + iconDesc={{ + side: 'left', + type: SideMenuOptionIconDescriptionType.CustomComponent, + value: ( + + ), + }} + /> + {isActionInProgress && + (item as ListedAccountInfo).author_url === + authorUrlWithInProgressAction && ( + + )} + + {!isLoading && !doesListedItemHaveActions(item) && ( + + Unable to load actions + + )} + + ); + }} + /> + )} + + + , + }} + /> + {isRequestingAccount && ( + + )} + + + + application.deviceInterface.openUrl('https://listed.to') + } + iconDesc={{ + side: 'left', + type: SideMenuOptionIconDescriptionType.CustomComponent, + value: , + }} + /> + + + + ); +}; diff --git a/src/screens/SideMenu/MainSideMenu.tsx b/src/screens/SideMenu/MainSideMenu.tsx index 11de27a2..d022e957 100644 --- a/src/screens/SideMenu/MainSideMenu.tsx +++ b/src/screens/SideMenu/MainSideMenu.tsx @@ -33,7 +33,7 @@ import { useStyles, } from './MainSideMenu.styled'; import { SideMenuHero } from './SideMenuHero'; -import { SideMenuOption, SideMenuSection } from './SideMenuSection'; +import { SideMenuOptionIconDescriptionType, SideMenuOption, SideMenuSection } from './SideMenuSection'; import { TagSelectionList } from './TagSelectionList'; type Props = { @@ -163,7 +163,7 @@ export const MainSideMenu = React.memo(({ drawerRef }: Props) => { const iconDescriptorForTheme = (currentTheme: SNTheme | MobileTheme) => { const desc = { - type: 'circle', + type: SideMenuOptionIconDescriptionType.Circle, side: 'right' as 'right', }; @@ -218,7 +218,7 @@ export const MainSideMenu = React.memo(({ drawerRef }: Props) => { text: 'Get More Themes', key: 'get-theme', iconDesc: { - type: 'icon', + type: SideMenuOptionIconDescriptionType.Icon, name: ThemeService.nameForIcon(ICON_BRUSH), side: 'right', size: 17, diff --git a/src/screens/SideMenu/NoteSideMenu.tsx b/src/screens/SideMenu/NoteSideMenu.tsx index 1853e2f3..65f11795 100644 --- a/src/screens/SideMenu/NoteSideMenu.tsx +++ b/src/screens/SideMenu/NoteSideMenu.tsx @@ -12,6 +12,7 @@ import { SCREEN_INPUT_MODAL_TAG, SCREEN_NOTE_HISTORY, } from '@Screens/screens'; +import { Listed } from '@Screens/SideMenu/Listed'; import { ButtonType, ComponentArea, @@ -52,7 +53,7 @@ import DrawerLayout from 'react-native-gesture-handler/DrawerLayout'; import Icon from 'react-native-vector-icons/Ionicons'; import { ThemeContext } from 'styled-components/native'; import { SafeAreaContainer, useStyles } from './NoteSideMenu.styled'; -import { SideMenuOption, SideMenuSection } from './SideMenuSection'; +import { SideMenuOption, SideMenuOptionIconDescriptionType, SideMenuSection } from './SideMenuSection'; import { TagSelectionList } from './TagSelectionList'; function sortAlphabetically(array: SNComponent[]): SNComponent[] { @@ -382,7 +383,7 @@ export const NoteSideMenu = React.memo((props: Props) => { text: 'Get More Editors', key: 'get-editors', iconDesc: { - type: 'icon', + type: SideMenuOptionIconDescriptionType.Icon, name: ThemeService.nameForIcon(ICON_MEDICAL), side: 'right', size: 17, @@ -496,7 +497,7 @@ export const NoteSideMenu = React.memo((props: Props) => { text: rawOption.text, key: rawOption.icon, iconDesc: { - type: 'icon', + type: SideMenuOptionIconDescriptionType.Icon, side: 'right' as 'right', name: ThemeService.nameForIcon(rawOption.icon), }, @@ -585,42 +586,70 @@ export const NoteSideMenu = React.memo((props: Props) => { return null; } + enum MenuSections { + OptionsSection = 'options-section', + EditorsSection = 'editors-section', + ListedSection = 'listed-section', + TagsSection = 'tags-section', + } + return ( ({ - key, - noteOptions, - editorComponents: editors, - onTagSelect, - selectedTags, - }) - )} - renderItem={({ item, index }) => - index === 0 ? ( - - ) : index === 1 ? ( - - ) : index === 2 ? ( - - ({ + key, + noteOptions, + editorComponents: editors, + onTagSelect, + selectedTags, + }))} + renderItem={({ item }) => { + const { + OptionsSection, + EditorsSection, + ListedSection, + TagsSection, + } = MenuSections; + + if (item.key === OptionsSection) { + return ( + + ); + } + if (item.key === EditorsSection) { + return ( + - - ) : null - } + ); + } + if (item.key === ListedSection) { + return ( + + + + ); + } + if (item.key === TagsSection) { + return ( + + + + ); + } + return null; + }} /> { if (!desc) { return null; } - if (desc.type === 'icon' && desc.name) { + if (desc.type === SideMenuOptionIconDescriptionType.Icon && desc.name) { return ( ); - } else if (desc.type === 'ascii') { + } + if (desc.type === SideMenuOptionIconDescriptionType.Ascii) { return {desc.value}; - } else if (desc.type === 'circle') { + } + if (desc.type === SideMenuOptionIconDescriptionType.Circle) { return ( { /> ); - } else { - return *; } + if (desc.type === SideMenuOptionIconDescriptionType.CustomComponent) { + return desc.value; + } + return *; }; export const SideMenuCell: React.FC = props => { diff --git a/src/screens/SideMenu/SideMenuSection.tsx b/src/screens/SideMenu/SideMenuSection.tsx index 25ff2460..ed2d9662 100644 --- a/src/screens/SideMenu/SideMenuSection.tsx +++ b/src/screens/SideMenu/SideMenuSection.tsx @@ -1,17 +1,24 @@ -import React, { useMemo, useState } from 'react'; +import React, { ReactElement, useMemo, useState } from 'react'; import { SideMenuCell } from './SideMenuCell'; import { CollapsedLabel, Header, Root, Title } from './SideMenuSection.styled'; +export enum SideMenuOptionIconDescriptionType { + Icon = 'icon', + Ascii = 'ascii', + Circle = 'circle', + CustomComponent = 'custom-component', +} + export type SideMenuOption = { text: string; subtext?: string; textClass?: 'info' | 'danger' | 'warning'; key?: string; iconDesc?: { - type: string; + type: SideMenuOptionIconDescriptionType; side?: 'left' | 'right'; name?: string; - value?: string; + value?: string | ReactElement; backgroundColor?: string; borderColor?: string; size?: number; diff --git a/src/screens/SideMenu/TagSelectionList.tsx b/src/screens/SideMenu/TagSelectionList.tsx index 9ea56037..0d8e4019 100644 --- a/src/screens/SideMenu/TagSelectionList.tsx +++ b/src/screens/SideMenu/TagSelectionList.tsx @@ -20,6 +20,7 @@ import React, { import { FlatList, ListRenderItem } from 'react-native'; import { SideMenuCell } from './SideMenuCell'; import { EmptyPlaceholder } from './TagSelectionList.styled'; +import {SideMenuOptionIconDescriptionType} from "@Screens/SideMenu/SideMenuSection"; type Props = { contentType: ContentType.Tag | ContentType.SmartTag; @@ -158,7 +159,7 @@ export const TagSelectionList = React.memo( text={title} iconDesc={{ side: 'left', - type: 'ascii', + type: SideMenuOptionIconDescriptionType.Ascii, value: '#', }} key={item.uuid} diff --git a/yarn.lock b/yarn.lock index 8d985ad5..54e381b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2526,39 +2526,47 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@standardnotes/auth@^3.16.1": - version "3.16.1" - resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.16.1.tgz#c73b3c70dfde1905998a6a27d91241ff5c7926dc" - integrity sha512-MSYfb80AVeERrZPiN15XG9e/ECv6UrVJ0R5h9jVIEJzxPKfmpVJVr2wH2ts3B6etjD3VYtUS7UNBXC/fYI4kuw== +"@standardnotes/auth@^3.16.4": + version "3.16.4" + resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.16.4.tgz#6293bd67cdc4055229f1d520b6f44b39c6053a7a" + integrity sha512-2tHsDnwQgGD3pOzKuSjo4yj8hLjATb70jzFnEWoEpyCdHTuGys9qSBElfi672hU4vg+/nXaHpdVUuD5DPzLaXg== dependencies: - "@standardnotes/common" "^1.11.0" + "@standardnotes/common" "^1.14.0" jsonwebtoken "^8.5.1" -"@standardnotes/common@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.11.0.tgz#5ed4be817a1f448e6eeb700d141dbfd40193aabe" - integrity sha512-8TKx7bCwIazhGD3wkWTV4rmwbERsyisPbVDn6UIm1lNktWjKDF5OL1D8omalpR5wdM5qmXX5njI1zll2cxlW7A== +"@standardnotes/common@^1.14.0": + version "1.14.0" + resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.14.0.tgz#c3b8e06fb8120524da8d135f2dc594998e5a5c3a" + integrity sha512-QA8JhWty7y/N62jdLyWuXzsVvDDeFwcQAH/DB/g5Mmaqlz9VlKcsbRmVl4wHLG3ur6n5Qj68aOhzCQd0p7f/WA== -"@standardnotes/components@^1.7.3": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.3.tgz#544521a5f0c5955c384fa7878003f4fdfcda860c" - integrity sha512-2AcxDdSFMK0G7h6R+EdMR2muzmFyqm0Qtl9znjQ3Bec4wGo9gpLpxlvotbihh230H+PTq4DJybX586bEs6HUKg== +"@standardnotes/components@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.5.tgz#2f199350779a8f99e9e536223d318b822bdf369f" + integrity sha512-7nyrrcgPAkCf6pjbAIO8qOM+22KQU0jMCIDX3b4GAS1jXM7DJDy5Frnk3oMHd9NeFhnbf0TQH4Nz4uEeid6/HA== -"@standardnotes/domain-events@^2.23.7": - version "2.23.7" - resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.23.7.tgz#ea8f4d38929249234125475c0a59deb6eb384b72" - integrity sha512-sRht/c0KXv0NwoIalWs+2ugQz1C0JfCRIs/5FAeRCWCbn/OgHytCqPuD73/hGgUU/J323tYwB5+/7gYan4EWJg== +"@standardnotes/domain-events@^2.23.14": + version "2.23.14" + resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.23.14.tgz#733e340c6d42935c90858380d7721150d1804574" + integrity sha512-DRPD0lGdVn/tbVyl97QGyyAcdUZd4qsETICCO882mG33HBN8Yc7st176U+izu3T5W3dlnTqE+MJUASj3UxVCvw== dependencies: - "@standardnotes/auth" "^3.16.1" - "@standardnotes/features" "^1.32.6" + "@standardnotes/auth" "^3.16.4" + "@standardnotes/features" "^1.32.11" -"@standardnotes/features@^1.32.6": - version "1.32.6" - resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.32.6.tgz#63856e4f4af1a56aa6533a5e214a43c4b2d8b510" - integrity sha512-GQJfDzYAAlRSccPWgAAT95hmUqmo9Z/m52uhOvgOwdQgwxOkHnYh60cdM/lnYrTBk0wv9MYPTFd+3vbMXy9/YQ== +"@standardnotes/features@^1.32.11": + version "1.32.11" + resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.32.11.tgz#43417e541bdf0ce8a10dfd68e8073fc1338f1888" + integrity sha512-ZheQibMz4t2A6LKWcTDDGc5760AnPLFnHFwsSp0O8YydI3yz+qjm3pFF8XNeAEwgSvOX1W1nlX3E/X5tCp5LgQ== dependencies: - "@standardnotes/auth" "^3.16.1" - "@standardnotes/common" "^1.11.0" + "@standardnotes/auth" "^3.16.4" + "@standardnotes/common" "^1.14.0" + +"@standardnotes/services@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@standardnotes/services/-/services-1.1.0.tgz#42f743f58fb4ab85627368ae6bcdf513079ef708" + integrity sha512-r4lqUO30iHmjWodUTv+2D8xeCgpYFvJrNzR/pBIlZsAKMSjskxPyIUvBdQvHWs0o4vjf7ZedhpEwi68XwUqO3w== + dependencies: + "@standardnotes/common" "^1.14.0" + "@standardnotes/utils" "^1.1.1" "@standardnotes/settings@^1.11.3": version "1.11.3" @@ -2570,28 +2578,39 @@ resolved "https://registry.yarnpkg.com/@standardnotes/sncrypto-common/-/sncrypto-common-1.7.0.tgz#6ad96afeaa031c26e45cbaf527bb511b803f998d" integrity sha512-Dke13reJMLQFXa7y9EqZYEeZG5Ouy+32qWEsQISLjLRPrTuNwyNXee2mdPh6c9uNZxOQwrdHxVGfqzJ2iy3RpQ== -"@standardnotes/snjs@2.61.0": - version "2.61.0" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.61.0.tgz#0628fdb17c97f810fda0a989557184e394e4e555" - integrity sha512-2j/WfHPMRxwD6K857HHCWZbmK2zL4nZc7a+jY0rgfZd4yzU/wFwy3iUxV//a/IDQ9XUKAFQnyVjGnMS/oaWzsA== +"@standardnotes/snjs@2.63.1": + version "2.63.1" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.63.1.tgz#0759be39e77304fcca11ea902aa9be7bb737e756" + integrity sha512-d32CE7/yS+qEGlOfHTDc0NPzCFXPaK2zxlCi/j68R9lT/3LuV/uc1o9eNK9a5Fgcbtbk55vbW0rUYjQQVwUF8A== dependencies: - "@standardnotes/auth" "^3.16.1" - "@standardnotes/common" "^1.11.0" - "@standardnotes/domain-events" "^2.23.7" - "@standardnotes/features" "^1.32.6" + "@standardnotes/auth" "^3.16.4" + "@standardnotes/common" "^1.14.0" + "@standardnotes/domain-events" "^2.23.14" + "@standardnotes/features" "^1.32.11" + "@standardnotes/services" "^1.1.0" "@standardnotes/settings" "^1.11.3" "@standardnotes/sncrypto-common" "^1.7.0" + "@standardnotes/utils" "^1.1.1" -"@standardnotes/stylekit@5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.5.0.tgz#24d2aef1529bbb09406f95acdd55ba138cf14958" - integrity sha512-feAdjOu0tBfpRJh5pH+urji40Xu72tJ2VRWxzkxXX1SYHMbgXnjBNs5R4IWko2kMIQwNGuBOvEg87S5w2/fdhw== +"@standardnotes/stylekit@5.9.0": + version "5.9.0" + resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.9.0.tgz#16d62623335091062238c850a930dedaa5ad6f1d" + integrity sha512-lIlEKwxKkQT+AttSmN40zvzWzfqpfI4VPTscZvRnWRqMQjYDEnSbcA1h0UDcT5tvnrna4RtsOiUL9o0KDx56sg== dependencies: "@reach/listbox" "^0.15.0" "@reach/menu-button" "^0.15.1" "@svgr/webpack" "^6.2.1" prop-types "^15.7.2" +"@standardnotes/utils@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@standardnotes/utils/-/utils-1.1.1.tgz#a936edd328b4e10b43b11ffc8b1626a499fa6659" + integrity sha512-LaB1Y4arvwuABT0fybJ9At6pPEAwsDooaldYPuvqyfQAWdeqRCBMHxRDCX6yunrrwBwk7UoTie9MRw6DF1igwg== + dependencies: + "@standardnotes/common" "^1.14.0" + dompurify "^2.3.4" + lodash "^4.17.19" + "@svgr/babel-plugin-add-jsx-attribute@^6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-6.0.0.tgz#bd6d1ff32a31b82b601e73672a789cc41e84fe18" @@ -4459,6 +4478,11 @@ domhandler@^4.2.0, domhandler@^4.3.0: dependencies: domelementtype "^2.2.0" +dompurify@^2.3.4: + version "2.3.6" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.6.tgz#2e019d7d7617aacac07cbbe3d88ae3ad354cf875" + integrity sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg== + domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"