diff --git a/app/assets/javascripts/components/ApplicationView.tsx b/app/assets/javascripts/components/ApplicationView.tsx index 556da59ac..36b95f40e 100644 --- a/app/assets/javascripts/components/ApplicationView.tsx +++ b/app/assets/javascripts/components/ApplicationView.tsx @@ -26,6 +26,7 @@ import { PermissionsModal } from './PermissionsModal'; import { RevisionHistoryModalWrapper } from './RevisionHistoryModal/RevisionHistoryModalWrapper'; import { PremiumModalProvider } from './Premium'; import { ConfirmSignoutContainer } from './ConfirmSignoutModal'; +import { TagsContextMenu } from './Tags/TagContextMenu'; type Props = { application: WebApplication; @@ -268,6 +269,8 @@ export class ApplicationView extends PureComponent { appState={this.appState} /> + + {
-
-
- {this.state.noteStatus?.message} +
+
+
+ {this.state.noteStatus?.message} +
+ {this.state.noteStatus?.desc && ( +
{this.state.noteStatus.desc}
+ )}
- {this.state.noteStatus?.desc && ( -
{this.state.noteStatus.desc}
- )}
{open && ( = observer( (component) => [ComponentArea.EditorStack, ComponentArea.TagsList].includes( component.area - ) && component.identifier !== FeatureIdentifier.FoldersComponent + ) && + component.identifier !== FeatureIdentifier.DeprecatedFoldersComponent ); setToggleableComponents(toggleableComponents); }, [application]); diff --git a/app/assets/javascripts/components/RevisionHistoryModal/SelectedRevisionContent.tsx b/app/assets/javascripts/components/RevisionHistoryModal/SelectedRevisionContent.tsx index 487f7e908..bca863be8 100644 --- a/app/assets/javascripts/components/RevisionHistoryModal/SelectedRevisionContent.tsx +++ b/app/assets/javascripts/components/RevisionHistoryModal/SelectedRevisionContent.tsx @@ -64,11 +64,14 @@ export const SelectedRevisionContent: FunctionComponent
{!componentViewer && ( -
+
{selectedRevision.payload.content.text.length ? ( -

+ ) : (

Empty note. diff --git a/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx b/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx index a0a7e4a55..d6405fd7d 100644 --- a/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx +++ b/app/assets/javascripts/components/Tags/SmartTagsListItem.tsx @@ -84,7 +84,7 @@ export const SmartTagsListItem: FunctionComponent = observer( }, [inputRef]); const onClickDelete = useCallback(() => { - tagsState.remove(tag); + tagsState.remove(tag, true); }, [tagsState, tag]); const isFaded = !tag.isAllTag; @@ -111,6 +111,7 @@ export const SmartTagsListItem: FunctionComponent = observer(
= observer( + ({ appState }) => { + const selectedTag = appState.tags.selected; + + if (!selectedTag) { + return null; + } + + const { contextMenuOpen, contextMenuPosition, contextMenuMaxHeight } = + appState.tags; + + const contextMenuRef = useRef(null); + const [closeOnBlur] = useCloseOnBlur(contextMenuRef, (open: boolean) => + appState.tags.setContextMenuOpen(open) + ); + + const reloadContextMenuLayout = useCallback(() => { + appState.tags.reloadContextMenuLayout(); + }, [appState.tags]); + + useEffect(() => { + window.addEventListener('resize', reloadContextMenuLayout); + return () => { + window.removeEventListener('resize', reloadContextMenuLayout); + }; + }, [reloadContextMenuLayout]); + + const onClickAddSubtag = useCallback(() => { + appState.tags.setContextMenuOpen(false); + appState.tags.setAddingSubtagTo(selectedTag); + }, [appState.tags, selectedTag]); + + const onClickRename = useCallback(() => { + appState.tags.setContextMenuOpen(false); + appState.tags.editingTag = selectedTag; + }, [appState.tags, selectedTag]); + + const onClickDelete = useCallback(() => { + appState.tags.remove(selectedTag, true); + }, [appState.tags, selectedTag]); + + return contextMenuOpen ? ( +
+ { + appState.tags.setContextMenuOpen(false); + }} + > + + + Add subtag + + + + Rename + + + + Delete + + +
+ ) : null; + } +); diff --git a/app/assets/javascripts/components/Tags/TagsList.tsx b/app/assets/javascripts/components/Tags/TagsList.tsx index 42eafd822..f5a0d3b8a 100644 --- a/app/assets/javascripts/components/Tags/TagsList.tsx +++ b/app/assets/javascripts/components/Tags/TagsList.tsx @@ -1,5 +1,6 @@ import { AppState } from '@/ui_models/app_state'; import { isMobile } from '@/utils'; +import { SNTag } from '@standardnotes/snjs'; import { observer } from 'mobx-react-lite'; import { FunctionComponent } from 'preact'; import { DndProvider } from 'react-dnd'; @@ -18,6 +19,20 @@ export const TagsList: FunctionComponent = observer(({ appState }) => { const backend = isMobile({ tablet: true }) ? TouchBackend : HTML5Backend; + const openTagContextMenu = (posX: number, posY: number) => { + appState.tags.setContextMenuClickLocation({ + x: posX, + y: posY, + }); + appState.tags.reloadContextMenuLayout(); + appState.tags.setContextMenuOpen(true); + }; + + const onContextMenu = (tag: SNTag, posX: number, posY: number) => { + appState.tags.selected = tag; + openTagContextMenu(posX, posY); + }; + return ( {allTags.length === 0 ? ( @@ -34,6 +49,7 @@ export const TagsList: FunctionComponent = observer(({ appState }) => { tag={tag} tagsState={tagsState} features={appState.features} + onContextMenu={onContextMenu} /> ); })} diff --git a/app/assets/javascripts/components/Tags/TagsListItem.tsx b/app/assets/javascripts/components/Tags/TagsListItem.tsx index 7c10a3d56..5e3cf1018 100644 --- a/app/assets/javascripts/components/Tags/TagsListItem.tsx +++ b/app/assets/javascripts/components/Tags/TagsListItem.tsx @@ -1,5 +1,6 @@ import { Icon } from '@/components/Icon'; import { usePremiumModal } from '@/components/Premium'; +import { KeyboardKey } from '@/services/ioService'; import { FeaturesState, TAG_FOLDERS_FEATURE_NAME, @@ -19,18 +20,23 @@ type Props = { tagsState: TagsState; features: FeaturesState; level: number; + onContextMenu: (tag: SNTag, posX: number, posY: number) => void; }; const PADDING_BASE_PX = 14; const PADDING_PER_LEVEL_PX = 21; export const TagsListItem: FunctionComponent = observer( - ({ tag, features, tagsState, level }) => { + ({ tag, features, tagsState, level, onContextMenu }) => { const [title, setTitle] = useState(tag.title || ''); + const [subtagTitle, setSubtagTitle] = useState(''); const inputRef = useRef(null); + const subtagInputRef = useRef(null); + const menuButtonRef = useRef(null); const isSelected = tagsState.selected === tag; const isEditing = tagsState.editingTag === tag; + const isAddingSubtag = tagsState.addingSubtagTo === tag; const noteCounts = computed(() => tagsState.getNotesCount(tag)); const childrenTags = computed(() => tagsState.getChildren(tag)).get(); @@ -83,9 +89,9 @@ export const TagsListItem: FunctionComponent = observer( [setTitle] ); - const onKeyUp = useCallback( + const onKeyDown = useCallback( (e: KeyboardEvent) => { - if (e.code === 'Enter') { + if (e.key === KeyboardKey.Enter) { inputRef.current?.blur(); e.preventDefault(); } @@ -99,17 +105,34 @@ export const TagsListItem: FunctionComponent = observer( } }, [inputRef, isEditing]); - const onClickRename = useCallback(() => { - tagsState.editingTag = tag; - }, [tagsState, tag]); + const onSubtagInput = useCallback( + (e: JSX.TargetedEvent) => { + const value = (e.target as HTMLInputElement).value; + setSubtagTitle(value); + }, + [] + ); - const onClickSave = useCallback(() => { - inputRef.current?.blur(); - }, [inputRef]); + const onSubtagInputBlur = useCallback(() => { + tagsState.createSubtagAndAssignParent(tag, subtagTitle); + setSubtagTitle(''); + }, [subtagTitle, tag, tagsState]); - const onClickDelete = useCallback(() => { - tagsState.remove(tag); - }, [tagsState, tag]); + const onSubtagKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === KeyboardKey.Enter) { + e.preventDefault(); + subtagInputRef.current?.blur(); + } + }, + [subtagInputRef] + ); + + useEffect(() => { + if (isAddingSubtag) { + subtagInputRef.current?.focus(); + } + }, [subtagInputRef, isAddingSubtag]); const [, dragRef] = useDrag( () => ({ @@ -148,10 +171,25 @@ export const TagsListItem: FunctionComponent = observer( const readyToDrop = isOver && canDrop; + const toggleContextMenu = () => { + if (!menuButtonRef.current) { + return; + } + + const contextMenuOpen = tagsState.contextMenuOpen; + const menuButtonRect = menuButtonRef.current?.getBoundingClientRect(); + + if (contextMenuOpen) { + tagsState.setContextMenuOpen(false); + } else { + onContextMenu(tag, menuButtonRect.right, menuButtonRect.top); + } + }; + return ( <> -
= observer( style={{ paddingLeft: `${level * PADDING_PER_LEVEL_PX + PADDING_BASE_PX}px`, }} + onContextMenu={(e: MouseEvent) => { + e.preventDefault(); + onContextMenu(tag, e.clientX, e.clientY); + }} > {!tag.errorDecrypting ? (
{hasAtLeastOneFolder && ( -
- +
+
)} -
+
= observer( -
{noteCounts.get()}
+
+ +
{noteCounts.get()}
+
) : null}
@@ -206,25 +266,34 @@ export const TagsListItem: FunctionComponent = observer( {tag.errorDecrypting && tag.waitingForKey && (
Waiting For Keys
)} - {isSelected && ( -
- {!isEditing && ( - - Rename - - )} - {isEditing && ( - - Save - - )} - - Delete - -
- )}
-
+ + {isAddingSubtag && ( +
+
+
+
+ +
+ +
+
+ )} {showChildren && ( <> {childrenTags.map((tag) => { @@ -235,6 +304,7 @@ export const TagsListItem: FunctionComponent = observer( tag={tag} tagsState={tagsState} features={features} + onContextMenu={onContextMenu} /> ); })} diff --git a/app/assets/javascripts/services/themeManager.ts b/app/assets/javascripts/services/themeManager.ts index 56d3aa172..11d0262c8 100644 --- a/app/assets/javascripts/services/themeManager.ts +++ b/app/assets/javascripts/services/themeManager.ts @@ -84,7 +84,7 @@ export class ThemeManager extends ApplicationService { break; } case ApplicationEvent.FeaturesUpdated: { - this.reloadThemeStatus(); + this.handleFeaturesUpdated(); break; } case ApplicationEvent.Launched: { @@ -119,7 +119,7 @@ export class ThemeManager extends ApplicationService { super.deinit(); } - private reloadThemeStatus(): void { + private handleFeaturesUpdated(): void { let hasChange = false; for (const themeUuid of this.activeThemes) { const theme = this.application.findItem(themeUuid) as SNTheme; @@ -139,6 +139,17 @@ export class ThemeManager extends ApplicationService { } } + const activeThemes = ( + this.application.getItems(ContentType.Theme) as SNTheme[] + ).filter((theme) => theme.active); + + for (const theme of activeThemes) { + if (!this.activeThemes.includes(theme.uuid)) { + this.activateTheme(theme); + hasChange = true; + } + } + if (hasChange) { this.cacheThemeState(); } diff --git a/app/assets/javascripts/strings.ts b/app/assets/javascripts/strings.ts index 45c7362cd..36e810f7d 100644 --- a/app/assets/javascripts/strings.ts +++ b/app/assets/javascripts/strings.ts @@ -20,7 +20,7 @@ export const STRING_NEW_UPDATE_READY = /** @tags */ export const STRING_DELETE_TAG = - 'Are you sure you want to delete this tag? Note: deleting a tag will not delete its notes.'; + 'Are you sure you want to delete this tag? Deleting a tag will not delete its subtags or its notes.'; export const STRING_MISSING_SYSTEM_TAG = 'We are missing a System Tag.'; diff --git a/app/assets/javascripts/ui_models/app_state/tags_state.ts b/app/assets/javascripts/ui_models/app_state/tags_state.ts index 4825f180a..4ba4c12b6 100644 --- a/app/assets/javascripts/ui_models/app_state/tags_state.ts +++ b/app/assets/javascripts/ui_models/app_state/tags_state.ts @@ -1,5 +1,9 @@ import { confirmDialog } from '@/services/alertService'; import { STRING_DELETE_TAG } from '@/strings'; +import { + MAX_MENU_SIZE_MULTIPLIER, + MENU_MARGIN_FROM_APP_BORDER, +} from '@/constants'; import { ComponentAction, ContentType, @@ -72,6 +76,15 @@ export class TagsState { selected_: AnyTag | undefined; previouslySelected_: AnyTag | undefined; editing_: SNTag | undefined; + addingSubtagTo: SNTag | undefined; + + contextMenuOpen = false; + contextMenuPosition: { top?: number; left: number; bottom?: number } = { + top: 0, + left: 0, + }; + contextMenuClickLocation: { x: number; y: number } = { x: 0, y: 0 }; + contextMenuMaxHeight: number | 'auto' = 'auto'; private readonly tagsCountsState: TagsCountsState; @@ -85,6 +98,7 @@ export class TagsState { this.selected_ = undefined; this.previouslySelected_ = undefined; this.editing_ = undefined; + this.addingSubtagTo = undefined; this.smartTags = this.application.getSmartTags(); this.selected_ = this.smartTags[0]; @@ -105,6 +119,9 @@ export class TagsState { selectedUuid: computed, editingTag: computed, + addingSubtagTo: observable, + setAddingSubtagTo: action, + assignParent: action, rootTags: computed, @@ -114,6 +131,15 @@ export class TagsState { undoCreateNewTag: action, save: action, remove: action, + + contextMenuOpen: observable, + contextMenuPosition: observable, + contextMenuMaxHeight: observable, + contextMenuClickLocation: observable, + setContextMenuOpen: action, + setContextMenuClickLocation: action, + setContextMenuPosition: action, + setContextMenuMaxHeight: action, }); appEventListeners.push( @@ -159,6 +185,114 @@ export class TagsState { ); } + async createSubtagAndAssignParent(parent: SNTag, title: string) { + const hasEmptyTitle = title.length === 0; + + if (hasEmptyTitle) { + this.setAddingSubtagTo(undefined); + return; + } + + const createdTag = await this.application.createTagOrSmartTag(title); + + const futureSiblings = this.application.getTagChildren(parent); + + if (!isValidFutureSiblings(this.application, futureSiblings, createdTag)) { + this.setAddingSubtagTo(undefined); + this.remove(createdTag, false); + return; + } + + this.assignParent(createdTag.uuid, parent.uuid); + + this.application.sync(); + + runInAction(() => { + this.selected = createdTag as SNTag; + }); + + this.setAddingSubtagTo(undefined); + } + + setAddingSubtagTo(tag: SNTag | undefined): void { + this.addingSubtagTo = tag; + } + + setContextMenuOpen(open: boolean): void { + this.contextMenuOpen = open; + } + + setContextMenuClickLocation(location: { x: number; y: number }): void { + this.contextMenuClickLocation = location; + } + + setContextMenuPosition(position: { + top?: number; + left: number; + bottom?: number; + }): void { + this.contextMenuPosition = position; + } + + setContextMenuMaxHeight(maxHeight: number | 'auto'): void { + this.contextMenuMaxHeight = maxHeight; + } + + reloadContextMenuLayout(): void { + const { clientHeight } = document.documentElement; + const defaultFontSize = window.getComputedStyle( + document.documentElement + ).fontSize; + const maxContextMenuHeight = + parseFloat(defaultFontSize) * MAX_MENU_SIZE_MULTIPLIER; + const footerElementRect = document + .getElementById('footer-bar') + ?.getBoundingClientRect(); + const footerHeightInPx = footerElementRect?.height; + + // Open up-bottom is default behavior + let openUpBottom = true; + + if (footerHeightInPx) { + const bottomSpace = + clientHeight - footerHeightInPx - this.contextMenuClickLocation.y; + const upSpace = this.contextMenuClickLocation.y; + + // If not enough space to open up-bottom + if (maxContextMenuHeight > bottomSpace) { + // If there's enough space, open bottom-up + if (upSpace > maxContextMenuHeight) { + openUpBottom = false; + this.setContextMenuMaxHeight('auto'); + // Else, reduce max height (menu will be scrollable) and open in whichever direction there's more space + } else { + if (upSpace > bottomSpace) { + this.setContextMenuMaxHeight(upSpace - MENU_MARGIN_FROM_APP_BORDER); + openUpBottom = false; + } else { + this.setContextMenuMaxHeight( + bottomSpace - MENU_MARGIN_FROM_APP_BORDER + ); + } + } + } else { + this.setContextMenuMaxHeight('auto'); + } + } + + if (openUpBottom) { + this.setContextMenuPosition({ + top: this.contextMenuClickLocation.y, + left: this.contextMenuClickLocation.x, + }); + } else { + this.setContextMenuPosition({ + bottom: clientHeight - this.contextMenuClickLocation.y, + left: this.contextMenuClickLocation.x, + }); + } + } + public get allLocalRootTags(): SNTag[] { if (this.editing_ && this.application.isTemplateItem(this.editing_)) { return [this.editing_, ...this.rootTags]; @@ -270,9 +404,9 @@ export class TagsState { this.selected_ = tag; } - public setExpanded(tag: SNTag, exapnded: boolean) { + public setExpanded(tag: SNTag, expanded: boolean) { this.application.changeAndSaveItem(tag.uuid, (mutator) => { - mutator.expanded = exapnded; + mutator.expanded = expanded; }); } @@ -312,13 +446,15 @@ export class TagsState { this.selected = previousTag; } - public async remove(tag: SNTag) { - if ( - await confirmDialog({ + public async remove(tag: SNTag, userTriggered: boolean) { + let shouldDelete = !userTriggered; + if (userTriggered) { + shouldDelete = await confirmDialog({ text: STRING_DELETE_TAG, confirmButtonStyle: 'danger', - }) - ) { + }); + } + if (shouldDelete) { this.application.deleteItem(tag); this.selected = this.smartTags[0]; } diff --git a/app/assets/javascripts/web_device_interface.ts b/app/assets/javascripts/web_device_interface.ts index 9997a9f48..c44371d70 100644 --- a/app/assets/javascripts/web_device_interface.ts +++ b/app/assets/javascripts/web_device_interface.ts @@ -1,13 +1,13 @@ import { - DeviceInterface, getGlobalScope, SNApplication, ApplicationIdentifier, + AbstractDevice, } from '@standardnotes/snjs'; import { Database } from '@/database'; import { Bridge } from './services/bridge'; -export class WebDeviceInterface extends DeviceInterface { +export class WebDeviceInterface extends AbstractDevice { private databases: Database[] = []; constructor(private bridge: Bridge) { diff --git a/app/assets/stylesheets/_editor.scss b/app/assets/stylesheets/_editor.scss index 5c209bd15..61629478a 100644 --- a/app/assets/stylesheets/_editor.scss +++ b/app/assets/stylesheets/_editor.scss @@ -64,17 +64,22 @@ $heading-height: 75px; } } - #save-status { + #save-status-container { + position: relative; + min-width: 15ch; + max-width: 15ch; + overflow: visible; margin-right: 20px; + } + + #save-status { font-size: calc(var(--sn-stylekit-base-font-size) - 2px); text-transform: none; font-weight: normal; text-align: right; - white-space: nowrap; .desc, .message:not(.warning):not(.danger) { - // color: var(--sn-stylekit-editor-foreground-color); opacity: 0.35; } } diff --git a/app/assets/stylesheets/_navigation.scss b/app/assets/stylesheets/_navigation.scss index e2b7c9437..2b5f461ea 100644 --- a/app/assets/stylesheets/_navigation.scss +++ b/app/assets/stylesheets/_navigation.scss @@ -61,6 +61,15 @@ $content-horizontal-padding: 16px; } } + .tag { + border: 0; + background-color: transparent; + + &:focus { + background-color: var(--sn-stylekit-secondary-contrast-background-color); + } + } + .tag, .root-drop { font-size: 14px; @@ -81,17 +90,17 @@ $content-horizontal-padding: 16px; .sn-icon { display: block; margin: 0 auto; - - &.hidden { - visibility: hidden; - } } - > .tag-fold { - width: 22px; + .tag-fold { + min-width: 22px; display: flex; align-items: center; height: 100%; + + @extend .border-0; + @extend .bg-transparent; + @extend .p-0; } > .tag-icon { @@ -147,12 +156,12 @@ $content-horizontal-padding: 16px; } } - > .count { + .count { padding-right: 4px; padding-top: 1px; font-weight: bold; color: var(--sn-stylekit-neutral-color); - min-width: 35px; + min-width: 15px; text-align: right; } } diff --git a/app/assets/stylesheets/_sn.scss b/app/assets/stylesheets/_sn.scss index a66a33bd7..10b7171b4 100644 --- a/app/assets/stylesheets/_sn.scss +++ b/app/assets/stylesheets/_sn.scss @@ -954,3 +954,15 @@ .sn-component .border-contrast { border-color: var(--sn-stylekit-contrast-border-color); } + +.resize-none { + resize: none; +} + +.visible { + visibility: visible; +} + +.invisible { + visibility: hidden; +} diff --git a/package.json b/package.json index 8d1fea7cd..1c4e0eb67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.11.1", + "version": "3.11.2", "license": "AGPL-3.0-or-later", "repository": { "type": "git", @@ -31,8 +31,8 @@ "@types/jest": "^27.4.0", "@types/lodash": "^4.14.178", "@types/react": "^17.0.39", - "@typescript-eslint/eslint-plugin": "^5.12.0", - "@typescript-eslint/parser": "^5.12.0", + "@typescript-eslint/eslint-plugin": "^5.12.1", + "@typescript-eslint/parser": "^5.12.1", "apply-loader": "^2.0.0", "babel-eslint": "^10.1.0", "babel-loader": "^8.2.3", @@ -41,7 +41,7 @@ "css-loader": "^6.6.0", "dotenv": "^16.0.0", "eslint": "^8.9.0", - "eslint-config-prettier": "^8.3.0", + "eslint-config-prettier": "^8.4.0", "eslint-plugin-react": "^7.28.0", "eslint-plugin-react-hooks": "^4.3.0", "file-loader": "^6.2.0", @@ -57,7 +57,7 @@ "pretty-quick": "^3.1.3", "sass-loader": "^12.6.0", "serve-static": "^1.14.2", - "@standardnotes/stylekit": "5.8.0", + "@standardnotes/stylekit": "5.9.0", "svg-jest": "^1.0.1", "ts-jest": "^27.1.3", "ts-loader": "^9.2.6", @@ -76,12 +76,12 @@ "@reach/dialog": "^0.16.2", "@reach/listbox": "^0.16.2", "@reach/tooltip": "^0.16.2", - "@standardnotes/components": "1.7.4", - "@standardnotes/features": "1.32.8", - "@standardnotes/snjs": "2.61.4", + "@standardnotes/components": "1.7.5", + "@standardnotes/features": "1.32.11", + "@standardnotes/snjs": "2.63.1", "@standardnotes/settings": "^1.11.3", "@standardnotes/sncrypto-web": "1.7.0", - "mobx": "^6.4.0", + "mobx": "^6.4.1", "mobx-react-lite": "^3.3.0", "preact": "^10.6.6", "qrcode.react": "^1.0.1", diff --git a/yarn.lock b/yarn.lock index 69347b519..aab7acb6f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2366,39 +2366,47 @@ dependencies: "@sinonjs/commons" "^1.7.0" -"@standardnotes/auth@^3.16.2": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@standardnotes/auth/-/auth-3.16.2.tgz#ad7352a2578d4a581a3210cf77fc884089c1b5f5" - integrity sha512-BSPdIZpON9lPo+uzTU1qyxWoLtsJ8DDFrlAiKWgXLud0mQwGDaFdZKJGJwgOc8AdPJbbLcaNiFDiSCRnpnoN9A== +"@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.12.0" + "@standardnotes/common" "^1.14.0" jsonwebtoken "^8.5.1" -"@standardnotes/common@^1.12.0": - version "1.12.0" - resolved "https://registry.yarnpkg.com/@standardnotes/common/-/common-1.12.0.tgz#971e542ea260fd794a20bac8451b56caca11cd87" - integrity sha512-GqwRdZz2s078Gd8Xyb4/Kup0uJB1BEBGFHjPn8ERoUOos0hSuu40ybxtUWguItM4D4SP7QCXhMIfRtDyM0g7TQ== +"@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.4": - version "1.7.4" - resolved "https://registry.yarnpkg.com/@standardnotes/components/-/components-1.7.4.tgz#77b17a424d411288a12366c65b6931729b2d73de" - integrity sha512-yExiJw1lyClRpQlML0/FbCvULJe8c4mPp0WvXq1IRE5R3x3MZ6LsCJgoqZAylIXki8Zvw17mxvwA4ywbd/ug0A== +"@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.11": - version "2.23.11" - resolved "https://registry.yarnpkg.com/@standardnotes/domain-events/-/domain-events-2.23.11.tgz#5cee6039e48983e49fcb04cb94b0f802e7745eeb" - integrity sha512-LTZovUtwpY2r5zVVbeQMLEnETqv1VuRIzsh6Gj+uEhBsJDlzorPPy40P3K/y5xSR4Ml8MQGqy1fBIjxpBBUKyQ== +"@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.2" - "@standardnotes/features" "^1.32.8" + "@standardnotes/auth" "^3.16.4" + "@standardnotes/features" "^1.32.11" -"@standardnotes/features@1.32.8", "@standardnotes/features@^1.32.8": - version "1.32.8" - resolved "https://registry.yarnpkg.com/@standardnotes/features/-/features-1.32.8.tgz#0bf36a66f0633d2e90d9f77ec8fa384eaae99ab8" - integrity sha512-nE6PMIzntGvqBUrxZJ+GIfND5Lw924NWTHbG4lNJb576OeW5SauOJV68n3nOYs0/edttsb9MldIaHMiP9pT4Vw== +"@standardnotes/features@1.32.11", "@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.2" - "@standardnotes/common" "^1.12.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" @@ -2419,28 +2427,39 @@ buffer "^6.0.3" libsodium-wrappers "^0.7.9" -"@standardnotes/snjs@2.61.4": - version "2.61.4" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.61.4.tgz#311fb0988ade6b67ca77d3515d591a58894057a8" - integrity sha512-3wgi53JrgN2HliszdHVvMGs7qJhehh/iVZOt12RxL+Gp5MN60H4sqW0uPH/FCHcJGr1zD8GXKF+hOWxFa6gQ/A== +"@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.2" - "@standardnotes/common" "^1.12.0" - "@standardnotes/domain-events" "^2.23.11" - "@standardnotes/features" "^1.32.8" + "@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.8.0": - version "5.8.0" - resolved "https://registry.yarnpkg.com/@standardnotes/stylekit/-/stylekit-5.8.0.tgz#d76a65bcd5e25ff09c99b871705492f6b5e627c3" - integrity sha512-txuEjuh2wx2FDt0xh9EZTr08svs36kAMn5chxOok3KZXYBCbWHRiapvUh1vWtiGAT27568tBqmrVejabPwLgvg== +"@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" @@ -2839,14 +2858,14 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.0.tgz#bb46dd7ce7015c0928b98af1e602118e97df6c70" - integrity sha512-fwCMkDimwHVeIOKeBHiZhRUfJXU8n6xW1FL9diDxAyGAFvKcH4csy0v7twivOQdQdA0KC8TDr7GGRd3L4Lv0rQ== +"@typescript-eslint/eslint-plugin@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz#b2cd3e288f250ce8332d5035a2ff65aba3374ac4" + integrity sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw== dependencies: - "@typescript-eslint/scope-manager" "5.12.0" - "@typescript-eslint/type-utils" "5.12.0" - "@typescript-eslint/utils" "5.12.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/type-utils" "5.12.1" + "@typescript-eslint/utils" "5.12.1" debug "^4.3.2" functional-red-black-tree "^1.0.1" ignore "^5.1.8" @@ -2854,69 +2873,69 @@ semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/parser@^5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.0.tgz#0ca669861813df99ce54916f66f524c625ed2434" - integrity sha512-MfSwg9JMBojMUoGjUmX+D2stoQj1CBYTCP0qnnVtu9A+YQXVKNtLjasYh+jozOcrb/wau8TCfWOkQTiOAruBog== +"@typescript-eslint/parser@^5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.12.1.tgz#b090289b553b8aa0899740d799d0f96e6f49771b" + integrity sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw== dependencies: - "@typescript-eslint/scope-manager" "5.12.0" - "@typescript-eslint/types" "5.12.0" - "@typescript-eslint/typescript-estree" "5.12.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" debug "^4.3.2" -"@typescript-eslint/scope-manager@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.0.tgz#59619e6e5e2b1ce6cb3948b56014d3a24da83f5e" - integrity sha512-GAMobtIJI8FGf1sLlUWNUm2IOkIjvn7laFWyRx7CLrv6nLBI7su+B7lbStqVlK5NdLvHRFiJo2HhiDF7Ki01WQ== +"@typescript-eslint/scope-manager@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz#58734fd45d2d1dec49641aacc075fba5f0968817" + integrity sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ== dependencies: - "@typescript-eslint/types" "5.12.0" - "@typescript-eslint/visitor-keys" "5.12.0" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" -"@typescript-eslint/type-utils@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.0.tgz#aaf45765de71c6d9707c66ccff76ec2b9aa31bb6" - integrity sha512-9j9rli3zEBV+ae7rlbBOotJcI6zfc6SHFMdKI9M3Nc0sy458LJ79Os+TPWeBBL96J9/e36rdJOfCuyRSgFAA0Q== +"@typescript-eslint/type-utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz#8d58c6a0bb176b5e9a91581cda1a7f91a114d3f0" + integrity sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg== dependencies: - "@typescript-eslint/utils" "5.12.0" + "@typescript-eslint/utils" "5.12.1" debug "^4.3.2" tsutils "^3.21.0" -"@typescript-eslint/types@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.0.tgz#5b4030a28222ee01e851836562c07769eecda0b8" - integrity sha512-JowqbwPf93nvf8fZn5XrPGFBdIK8+yx5UEGs2QFAYFI8IWYfrzz+6zqlurGr2ctShMaJxqwsqmra3WXWjH1nRQ== +"@typescript-eslint/types@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.12.1.tgz#46a36a28ff4d946821b58fe5a73c81dc2e12aa89" + integrity sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA== -"@typescript-eslint/typescript-estree@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.0.tgz#cabf545fd592722f0e2b4104711e63bf89525cd2" - integrity sha512-Dd9gVeOqt38QHR0BEA8oRaT65WYqPYbIc5tRFQPkfLquVEFPD1HAtbZT98TLBkEcCkvwDYOAvuSvAD9DnQhMfQ== +"@typescript-eslint/typescript-estree@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz#6a9425b9c305bcbc38e2d1d9a24c08e15e02b722" + integrity sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw== dependencies: - "@typescript-eslint/types" "5.12.0" - "@typescript-eslint/visitor-keys" "5.12.0" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/visitor-keys" "5.12.1" debug "^4.3.2" globby "^11.0.4" is-glob "^4.0.3" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/utils@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.0.tgz#92fd3193191621ab863add2f553a7b38b65646af" - integrity sha512-k4J2WovnMPGI4PzKgDtQdNrCnmBHpMUFy21qjX2CoPdoBcSBIMvVBr9P2YDP8jOqZOeK3ThOL6VO/sy6jtnvzw== +"@typescript-eslint/utils@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.12.1.tgz#447c24a05d9c33f9c6c64cb48f251f2371eef920" + integrity sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ== dependencies: "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.12.0" - "@typescript-eslint/types" "5.12.0" - "@typescript-eslint/typescript-estree" "5.12.0" + "@typescript-eslint/scope-manager" "5.12.1" + "@typescript-eslint/types" "5.12.1" + "@typescript-eslint/typescript-estree" "5.12.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/visitor-keys@5.12.0": - version "5.12.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.0.tgz#1ac9352ed140b07ba144ebf371b743fdf537ec16" - integrity sha512-cFwTlgnMV6TgezQynx2c/4/tx9Tufbuo9LPzmWqyRC3QC4qTGkAG1C6pBr0/4I10PAI/FlYunI3vJjIcu+ZHMg== +"@typescript-eslint/visitor-keys@5.12.1": + version "5.12.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz#f722da106c8f9695ae5640574225e45af3e52ec3" + integrity sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A== dependencies: - "@typescript-eslint/types" "5.12.0" + "@typescript-eslint/types" "5.12.1" eslint-visitor-keys "^3.0.0" "@webassemblyjs/ast@1.11.1": @@ -4476,6 +4495,11 @@ domhandler@^4.0.0, domhandler@^4.2.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@^2.5.2, domutils@^2.6.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" @@ -4736,10 +4760,10 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" -eslint-config-prettier@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" - integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== +eslint-config-prettier@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.4.0.tgz#8e6d17c7436649e98c4c2189868562921ef563de" + integrity sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw== eslint-plugin-react-hooks@^4.3.0: version "4.3.0" @@ -7283,10 +7307,10 @@ mobx-react-lite@^3.3.0: resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-3.3.0.tgz#7174e807201943beff6f9d3701492314c9fc0db3" integrity sha512-U/kMSFtV/bNVgY01FuiGWpRkaQVHozBq5CEBZltFvPt4FcV111hEWkgwqVg9GPPZSEuEdV438PEz8mk8mKpYlA== -mobx@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.4.0.tgz#71beda560230527f75ad150638f061af9d9f5312" - integrity sha512-HluTl14lJjL1xeUfXekDstHT/RqdxtmgIQ+75eMXsy9zAwt5vOWMdrbYD/sLS3CAKTo7ctIZi6cI2aX47Fk05g== +mobx@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.4.1.tgz#c1d0eeb37ceb31bb2020a85f6bf856782d47fe60" + integrity sha512-NFXx0uMbGBgsa0uxhH099L8cMuoRQWh01q6Sf0ZX/3hFU7svJ7yfTD+1LnLMa5wzY/b7gImAeMsR1p0wordDnA== mri@^1.1.5: version "1.2.0"