Compare commits

...
Author SHA1 Message Date
StandardNotes CI a96323dfff chore(release): publish
- @standardnotes/[email protected].0
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].1
 - @standardnotes/[email protected].0
 - @standardnotes/[email protected].0
2022-10-24 13:18:36 +00:00
Aman Harwara c3212b019e fix: lint 2022-10-24 18:20:56 +05:30
Karol Sójko 0c44ad6c8e feat(web): add accepting subscription invites from UI 2022-10-24 14:30:28 +02:00
StandardNotes CI a4245aee6f chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].7
2022-10-24 09:04:24 +00:00
Aman Harwara 4181d7ff2c fix: dont show item list "hover" indicator on mobile 2022-10-24 14:06:02 +05:30
StandardNotes CI 337ae6009e chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].6
2022-10-23 16:44:21 +00:00
Aman Harwara bb63cbe2d1 fix: listed menu closing when clicking inside challenge modal (#1863) 2022-10-23 21:46:23 +05:30
Mo bda16b88c0 fix(web): emoji length computation (#1864) 2022-10-23 11:04:17 -05:00
StandardNotes CI 1173a392c5 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].5
2022-10-23 15:37:00 +00:00
Aman Harwara 9a509a79c0 fix: note option changes not updating correctly (#1862) 2022-10-23 20:36:29 +05:30
StandardNotes CI 9dc51f51b2 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].4
2022-10-23 06:28:39 +00:00
Aman Harwara f1f0d65dd5 Merge branch 'main' of github.com:standardnotes/app 2022-10-23 11:30:09 +05:30
Aman Harwara 47b3286235 fix: new note button on mobile when no account 2022-10-23 11:29:46 +05:30
StandardNotes CI 166953de20 chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].3
2022-10-23 05:40:52 +00:00
Aman Harwara b98f5e2d02 fix: link autocomplete input keyboard navigation (#1859) 2022-10-23 10:41:19 +05:30
StandardNotes CI 5dd3d521cb chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].2
2022-10-22 12:35:16 +00:00
Aman Harwara fc6c6bad2c fix: hide items list button on desktop 2022-10-22 17:35:37 +05:30
StandardNotes CI e9bf7d336b chore(release): publish
- @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected]
 - @standardnotes/[email protected].1
2022-10-21 18:42:09 +00:00
Aman Harwara e63b4f0592 fix: new tag creation 2022-10-21 23:35:27 +05:30
92 changed files with 1321 additions and 118 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.18.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
### Features
* **web:** add accepting subscription invites from UI ([0c44ad6](https://github.com/standardnotes/app/commit/0c44ad6c8eace6d5fe957fa75c205c66c5f590b4))
## [1.17.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/api
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/api",
"version": "1.17.2",
"version": "1.18.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -38,7 +38,7 @@ describe('SubscriptionServer', () => {
})
it('should accept an invite to a shared subscription', async () => {
httpService.get = jest.fn().mockReturnValue({
httpService.post = jest.fn().mockReturnValue({
data: { success: true },
} as jest.Mocked<SubscriptionInviteAcceptResponse>)
@@ -17,7 +17,7 @@ export class SubscriptionServer implements SubscriptionServerInterface {
constructor(private httpService: HttpServiceInterface) {}
async acceptInvite(params: SubscriptionInviteAcceptRequestParams): Promise<SubscriptionInviteAcceptResponse> {
const response = await this.httpService.get(Paths.v1.acceptInvite(params.inviteUuid), params)
const response = await this.httpService.post(Paths.v1.acceptInvite(params.inviteUuid), params)
return response as SubscriptionInviteAcceptResponse
}
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.23.244](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.243](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.242](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.241](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.240](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.239](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.238](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-22)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.237](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/desktop
## [3.23.236](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/desktop
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@standardnotes/desktop",
"main": "./app/dist/index.js",
"version": "3.23.236",
"version": "3.23.244",
"license": "AGPL-3.0-or-later",
"author": "Standard Notes.",
"private": true,
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [3.43.31](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.30](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.29](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.28](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.27](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.26](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.25](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-22)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.24](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/mobile
## [3.43.23](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/mobile
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/mobile",
"version": "3.43.23",
"version": "3.43.31",
"author": "Standard Notes.",
"private": true,
"license": "AGPL-3.0-or-later",
+32
View File
@@ -3,6 +3,38 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.173](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.172](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.171](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.170](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.169](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.168](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.167](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-22)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.166](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/releases
## [1.3.165](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/releases
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/releases",
"version": "1.3.165",
"version": "1.3.173",
"license": "AGPL-3.0-or-later",
"main": "dist/releases.json",
"types": "dist/index.d.ts",
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.35.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
### Features
* **web:** add accepting subscription invites from UI ([0c44ad6](https://github.com/standardnotes/app/commit/0c44ad6c8eace6d5fe957fa75c205c66c5f590b4))
## [1.34.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/services",
"version": "1.34.4",
"version": "1.35.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -5,4 +5,5 @@ export interface SubscriptionClientInterface {
listSubscriptionInvitations(): Promise<Invitation[]>
inviteToSubscription(inviteeEmail: string): Promise<boolean>
cancelInvitation(inviteUuid: Uuid): Promise<boolean>
acceptInvitation(inviteUuid: Uuid): Promise<{ success: true } | { success: false; message: string }>
}
@@ -12,6 +12,7 @@ describe('SubscriptionManager', () => {
beforeEach(() => {
subscriptionApiService = {} as jest.Mocked<SubscriptionApiServiceInterface>
subscriptionApiService.cancelInvite = jest.fn()
subscriptionApiService.acceptInvite = jest.fn()
subscriptionApiService.invite = jest.fn()
subscriptionApiService.listInvites = jest.fn()
@@ -80,4 +81,27 @@ describe('SubscriptionManager', () => {
expect(await createManager().listSubscriptionInvitations()).toEqual([])
})
it('should accept invite to a shared subscription', async () => {
subscriptionApiService.acceptInvite = jest.fn().mockReturnValue({ data: { success: true } })
expect(await createManager().acceptInvitation('1-2-3')).toEqual({ success: true })
})
it('should not accept invite if the api fails to do so', async () => {
subscriptionApiService.acceptInvite = jest.fn().mockReturnValue({ data: { error: { message: 'foobar' } } })
expect(await createManager().acceptInvitation('1-2-3')).toEqual({ success: false, message: 'foobar' })
})
it('should not accept invite if the api throws an error', async () => {
subscriptionApiService.acceptInvite = jest.fn().mockImplementation(() => {
throw new Error('Oops')
})
expect(await createManager().acceptInvitation('1-2-3')).toEqual({
success: false,
message: 'Could not accept invitation.',
})
})
})
@@ -13,6 +13,20 @@ export class SubscriptionManager extends AbstractService implements Subscription
super(internalEventBus)
}
async acceptInvitation(inviteUuid: string): Promise<{ success: true } | { success: false; message: string }> {
try {
const result = await this.subscriptionApiService.acceptInvite(inviteUuid)
if (result.data.error) {
return { success: false, message: result.data.error.message }
}
return result.data
} catch (error) {
return { success: false, message: 'Could not accept invitation.' }
}
}
async listSubscriptionInvitations(): Promise<Invitation[]> {
try {
const response = await this.subscriptionApiService.listInvites()
+4
View File
@@ -3,6 +3,10 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [2.143.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
**Note:** Version bump only for package @standardnotes/snjs
# [2.143.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
### Features
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/snjs",
"version": "2.143.0",
"version": "2.143.1",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
+6
View File
@@ -3,6 +3,12 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.10.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
### Features
* **web:** add accepting subscription invites from UI ([0c44ad6](https://github.com/standardnotes/app/commit/0c44ad6c8eace6d5fe957fa75c205c66c5f590b4))
## [1.9.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
**Note:** Version bump only for package @standardnotes/ui-services
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/ui-services",
"version": "1.9.2",
"version": "1.10.0",
"engines": {
"node": ">=16.0.0 <17.0.0"
},
@@ -5,6 +5,7 @@ import {
InternalEventBusInterface,
} from '@standardnotes/services'
import { RootQueryParam } from './RootQueryParam'
import { RouteParser } from './RouteParser'
import { RouteParserInterface } from './RouteParserInterface'
import { RouteServiceEvent } from './RouteServiceEvent'
@@ -30,13 +31,13 @@ export class RouteService
this.unsubApp()
}
public getRoute(): RouteParserInterface {
getRoute(): RouteParserInterface {
return new RouteParser(window.location.href)
}
public removeSettingsFromURLQueryParameters() {
removeQueryParameterFromURL(param: RootQueryParam): void {
const urlSearchParams = new URLSearchParams(window.location.search)
urlSearchParams.delete('settings')
urlSearchParams.delete(param)
const newUrl = `${window.location.origin}${window.location.pathname}${urlSearchParams.toString()}`
window.history.replaceState(null, document.title, newUrl)
@@ -1,7 +1,8 @@
import { RootQueryParam } from './RootQueryParam'
import { RouteParserInterface } from './RouteParserInterface'
export interface RouteServiceInterface {
deinit(): void
getRoute(): RouteParserInterface
removeSettingsFromURLQueryParameters(): void
removeQueryParameterFromURL(param: RootQueryParam): void
}
@@ -0,0 +1,12 @@
import { addToast, ToastType } from '@standardnotes/toast'
import { ToastServiceInterface } from './ToastServiceInterface'
export class ToastService implements ToastServiceInterface {
showToast(type: ToastType, message: string): void {
addToast({
type: type,
message,
})
}
}
@@ -0,0 +1,5 @@
import { ToastType } from '@standardnotes/toast'
export interface ToastServiceInterface {
showToast(type: ToastType, message: string): void
}
+4
View File
@@ -8,7 +8,9 @@ export * from './Route/Params/OnboardingParams'
export * from './Route/Params/PurchaseParams'
export * from './Route/Params/SettingsParams'
export * from './Route/Params/SubscriptionInviteParams'
export * from './Route/RootQueryParam'
export * from './Route/RouteParser'
export * from './Route/RouteParserInterface'
export * from './Route/RouteType'
export * from './Route/RouteService'
export * from './Route/RouteServiceInterface'
@@ -16,3 +18,5 @@ export * from './Route/RouteServiceEvent'
export * from './Security/AutolockService'
export * from './Storage/LocalStorage'
export * from './Theme/ThemeManager'
export * from './Toast/ToastService'
export * from './Toast/ToastServiceInterface'
+53
View File
@@ -3,6 +3,59 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [3.85.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
### Bug Fixes
* lint ([c3212b0](https://github.com/standardnotes/app/commit/c3212b019e93a4684c7914b02fb94b239e99c7ff))
### Features
* **web:** add accepting subscription invites from UI ([0c44ad6](https://github.com/standardnotes/app/commit/0c44ad6c8eace6d5fe957fa75c205c66c5f590b4))
## [3.84.7](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-24)
### Bug Fixes
* dont show item list "hover" indicator on mobile ([4181d7f](https://github.com/standardnotes/app/commit/4181d7ff2c6ff76bfd2eeaea5fa770d04062fb7c))
## [3.84.6](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
### Bug Fixes
* listed menu closing when clicking inside challenge modal ([#1863](https://github.com/standardnotes/app/issues/1863)) ([bb63cbe](https://github.com/standardnotes/app/commit/bb63cbe2d15dd47d62a2cc34f824ed4bec6091de))
* **web:** emoji length computation ([#1864](https://github.com/standardnotes/app/issues/1864)) ([bda16b8](https://github.com/standardnotes/app/commit/bda16b88c0708bb28f2b7da2fdf4cad2af1936d5))
## [3.84.5](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
### Bug Fixes
* note option changes not updating correctly ([#1862](https://github.com/standardnotes/app/issues/1862)) ([9a509a7](https://github.com/standardnotes/app/commit/9a509a79c0e226b561d6606bf96907086326ae8f))
## [3.84.4](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
### Bug Fixes
* new note button on mobile when no account ([47b3286](https://github.com/standardnotes/app/commit/47b3286235da7b5f63aef5fbe0d8c9b34d1f4558))
## [3.84.3](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-23)
### Bug Fixes
* link autocomplete input keyboard navigation ([#1859](https://github.com/standardnotes/app/issues/1859)) ([b98f5e2](https://github.com/standardnotes/app/commit/b98f5e2d02d77b65e9e7a08b73fb8d22a467f7ec))
## [3.84.2](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-22)
### Bug Fixes
* hide items list button on desktop ([fc6c6ba](https://github.com/standardnotes/app/commit/fc6c6bad2ca0e8ec8b7e1410a6a88713ec7e6ec3))
## [3.84.1](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
### Bug Fixes
* new tag creation ([e63b4f0](https://github.com/standardnotes/app/commit/e63b4f0592ed32ecd3cdb01e84c9ca47d61fe243))
# [3.84.0](https://github.com/standardnotes/app/compare/@standardnotes/[email protected]...@standardnotes/[email protected]) (2022-10-21)
### Features
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@standardnotes/web",
"version": "3.84.0",
"version": "3.85.0",
"license": "AGPL-3.0-or-later",
"main": "dist/app.js",
"author": "Standard Notes.",
@@ -30,7 +30,7 @@
"@babel/preset-env": "*",
"@babel/preset-typescript": "^7.18.6",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.7",
"@types/jest": "^29.0.2",
"@types/jest": "^29.2.0",
"@types/react": "^18.0.20",
"@types/react-dom": "^18.0.6",
"@types/styled-components": "^5.1.26",
@@ -47,8 +47,8 @@
"eslint-plugin-react-hooks": "^4.6.0",
"html-webpack-plugin": "^5.5.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^28.1.2",
"jest-environment-jsdom": "^28.1.2",
"jest": "^29.2.1",
"jest-environment-jsdom": "^29.2.1",
"lint-staged": ">=12",
"mini-css-extract-plugin": "^2.6.1",
"node-sass": "*",
@@ -61,8 +61,8 @@
"sass-loader": "*",
"svg-jest": "^1.0.1",
"tailwindcss": "^3.1.8",
"ts-jest": "^28.0.5",
"ts-loader": "^9.3.1",
"ts-jest": "^29.0.3",
"ts-loader": "^9.4.1",
"typescript": "*",
"webpack": "*",
"webpack-dev-server": "*",
@@ -255,8 +255,8 @@ const ContentListView: FunctionComponent<Props> = ({
return
}
for (const file of files) {
void filesController.uploadNewFile(file)
for (let i = 0; i < files.length; i++) {
void filesController.uploadNewFile(files[i])
}
}}
/>
@@ -83,7 +83,7 @@ const ContentListHeader = ({
</Popover>
</div>
<button
className="absolute bottom-6 right-6 ml-3 flex h-13 w-13 cursor-pointer items-center justify-center rounded-full border border-solid border-transparent bg-info text-info-contrast hover:brightness-125 md:static md:h-8 md:w-8"
className="absolute bottom-6 right-6 z-editor-title-bar ml-3 flex h-13 w-13 cursor-pointer items-center justify-center rounded-full border border-solid border-transparent bg-info text-info-contrast hover:brightness-125 md:static md:h-8 md:w-8"
title={addButtonLabel}
aria-label={addButtonLabel}
onClick={addNewItem}
@@ -0,0 +1,13 @@
/**
* @jest-environment jsdom
*/
import { getEmojiLength } from './EmojiLength'
describe('emoji length', () => {
it('returns the correct length', () => {
expect(getEmojiLength('✍️')).toEqual(1)
expect(getEmojiLength('👩‍👩‍👧‍👦')).toEqual(1)
expect(getEmojiLength('👩‍❤️‍💋‍👩')).toEqual(1)
})
})
@@ -0,0 +1,7 @@
export function getEmojiLength(emoji: string): number {
try {
return [...new Intl.Segmenter().segment(emoji)].length
} catch (error) {
return [...emoji].length
}
}
@@ -2,6 +2,7 @@ import { EmojiString, Platform, VectorIconNameOrEmoji } from '@standardnotes/snj
import { FunctionComponent, useMemo, useRef, useState } from 'react'
import Dropdown from '../Dropdown/Dropdown'
import { DropdownItem } from '../Dropdown/DropdownItem'
import { getEmojiLength } from './EmojiLength'
import { isIconEmoji } from './Icon'
import { IconNameToSvgMapping } from './IconNameToSvgMapping'
import { IconPickerType } from './IconPickerType'
@@ -72,7 +73,7 @@ const IconPicker = ({ selectedValue, onIconChange, platform, className }: Props)
const handleEmojiChange = (value: EmojiString) => {
setEmojiInputValue(value)
const emojiLength = [...value].length
const emojiLength = getEmojiLength(value)
if (emojiLength === 1) {
onIconChange(value)
emojiInputRef.current?.blur()
@@ -92,6 +92,7 @@ const ItemLinkAutocompleteInput = ({ linkingController, focusPreviousItem, focus
break
case KeyboardKey.Down:
if (searchQuery.length > 0) {
event.preventDefault()
searchResultsMenuRef.current?.focus()
}
break
@@ -19,7 +19,7 @@ const MobileItemsListButton = () => {
return (
<RoundIconButton
className="mr-3"
className="mr-3 md:hidden pointer-coarse:md-only:flex pointer-coarse:lg-only:flex"
onClick={() => {
if (isTabletScreenSize) {
toggleNotesListOnTablets()
@@ -898,8 +898,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
const observer = new MutationObserver((records) => {
for (const record of records) {
const removedNodes = record.removedNodes.values()
for (const node of removedNodes) {
record.removedNodes.forEach((node) => {
if (node === editor) {
this.removeTabObserver?.()
this.removeTabObserver = undefined
@@ -907,7 +906,7 @@ class NoteView extends PureComponent<NoteViewProps, State> {
editor.removeEventListener('scroll', this.resetScrollPosition)
this.scrollPosition = 0
}
}
})
}
})
@@ -28,8 +28,9 @@ export const usePopoverCloseOnClickOutside = ({
const isAnchorElement = anchorElement ? anchorElement === event.target || anchorElement.contains(target) : false
const closestPopoverId = target.closest('[data-popover]')?.getAttribute('data-popover')
const isDescendantOfChildPopover = closestPopoverId && childPopovers.has(closestPopoverId)
const isDescendantOfChallengeModal = !!target.closest('.challenge-modal')
if (!isDescendantOfMenu && !isAnchorElement && !isDescendantOfChildPopover) {
if (!isDescendantOfMenu && !isAnchorElement && !isDescendantOfChildPopover && !isDescendantOfChallengeModal) {
togglePopover()
}
}
@@ -522,6 +522,7 @@ export class NavigationController
runInAction(() => {
this.editing_ = newTag
this.editingFrom = 'all'
})
}
@@ -80,7 +80,7 @@ export class NotesController extends AbstractViewController {
}
public get selectedNotes(): SNNote[] {
return this.selectionController.getSelectedItems<SNNote>(ContentType.Note)
return this.selectionController.getFilteredSelectedItems<SNNote>(ContentType.Note)
}
get firstSelectedNote(): SNNote | undefined {
@@ -1,6 +1,6 @@
import { InternalEventBus } from '@standardnotes/snjs'
import { action, computed, makeObservable, observable } from 'mobx'
import { PreferenceId } from '@standardnotes/ui-services'
import { PreferenceId, RootQueryParam } from '@standardnotes/ui-services'
import { AbstractViewController } from './Abstract/AbstractViewController'
import { WebApplication } from '@/Application/Application'
@@ -34,7 +34,7 @@ export class PreferencesController extends AbstractViewController {
closePreferences = (): void => {
this._open = false
this.currentPane = DEFAULT_PANE
this.application.routeService.removeSettingsFromURLQueryParameters()
this.application.routeService.removeQueryParameterFromURL(RootQueryParam.Settings)
}
get isOpen(): boolean {
@@ -26,6 +26,7 @@ export class SelectedItemsController
{
lastSelectedItem: ListableContentItem | undefined
selectedUuids: Set<UuidString> = observable(new Set<UuidString>())
selectedItems: Record<UuidString, ListableContentItem> = {}
private itemListController!: ItemListController
override deinit(): void {
@@ -38,6 +39,7 @@ export class SelectedItemsController
makeObservable(this, {
selectedUuids: observable,
selectedItems: observable,
selectedItemsCount: computed,
selectedFiles: computed,
@@ -46,6 +48,7 @@ export class SelectedItemsController
selectItem: action,
setSelectedUuids: action,
setSelectedItems: action,
hydrateFromPersistedValue: action,
})
@@ -82,13 +85,22 @@ export class SelectedItemsController
this.itemListController = itemListController
this.disposers.push(
this.application.streamItems<SNNote | FileItem>([ContentType.Note, ContentType.File], ({ removed }) => {
runInAction(() => {
for (const removedNote of removed) {
this.removeFromSelectedUuids(removedNote.uuid)
}
})
}),
this.application.streamItems<SNNote | FileItem>(
[ContentType.Note, ContentType.File],
({ changed, inserted, removed }) => {
runInAction(() => {
for (const removedItem of removed) {
this.removeSelectedItem(removedItem.uuid)
}
for (const item of [...changed, ...inserted]) {
if (this.selectedItems[item.uuid]) {
this.selectedItems[item.uuid] = item
}
}
})
},
),
)
}
@@ -97,11 +109,11 @@ export class SelectedItemsController
}
get selectedItemsCount(): number {
return this.selectedUuids.size
return Object.keys(this.selectedItems).length
}
get selectedFiles(): FileItem[] {
return this.getSelectedItems<FileItem>(ContentType.File)
return this.getFilteredSelectedItems<FileItem>(ContentType.File)
}
get selectedFilesCount(): number {
@@ -109,31 +121,37 @@ export class SelectedItemsController
}
get firstSelectedItem() {
return this.application.items.findSureItem(Array.from(this.selectedUuids)[0]) as ListableContentItem
return Object.values(this.selectedItems)[0]
}
getSelectedItems = <T extends ListableContentItem = ListableContentItem>(contentType?: ContentType): T[] => {
getSelectedItems = () => {
const uuids = Array.from(this.selectedUuids)
return uuids.length > 0
? (uuids
.map((uuid) => this.application.items.findSureItem(uuid))
.filter((item) => {
return !contentType ? true : item.content_type === contentType
}) as T[])
: []
return uuids.map((uuid) => this.application.items.findSureItem<SNNote | FileItem>(uuid)).filter((item) => !!item)
}
getFilteredSelectedItems = <T extends ListableContentItem = ListableContentItem>(contentType?: ContentType): T[] => {
return Object.values(this.selectedItems).filter((item) => {
return !contentType ? true : item.content_type === contentType
}) as T[]
}
setSelectedItems = () => {
this.selectedItems = Object.fromEntries(this.getSelectedItems().map((item) => [item.uuid, item]))
}
setSelectedUuids = (selectedUuids: Set<UuidString>) => {
this.selectedUuids = new Set(selectedUuids)
this.setSelectedItems()
}
private removeFromSelectedUuids = (uuid: UuidString) => {
private removeSelectedItem = (uuid: UuidString) => {
this.selectedUuids.delete(uuid)
this.setSelectedUuids(this.selectedUuids)
delete this.selectedItems[uuid]
}
public deselectItem = (item: { uuid: ListableContentItem['uuid'] }): void => {
this.removeFromSelectedUuids(item.uuid)
this.removeSelectedItem(item.uuid)
if (item.uuid === this.lastSelectedItem?.uuid) {
this.lastSelectedItem = undefined
@@ -244,7 +262,7 @@ export class SelectedItemsController
if (userTriggered && (hasMeta || hasCtrl)) {
if (this.selectedUuids.has(uuid) && hasMoreThanOneSelected) {
this.removeFromSelectedUuids(uuid)
this.removeSelectedItem(uuid)
} else if (isAuthorizedForAccess) {
this.setSelectedUuids(this.selectedUuids.add(uuid))
this.lastSelectedItem = item
@@ -1,5 +1,5 @@
import { PaneController } from './PaneController'
import { storage, StorageKey } from '@standardnotes/ui-services'
import { storage, StorageKey, ToastService, ToastServiceInterface } from '@standardnotes/ui-services'
import { WebApplication } from '@/Application/Application'
import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController'
import { destroyAllObjectProperties } from '@/Utils'
@@ -71,6 +71,7 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
private subscriptionManager: SubscriptionClientInterface
private persistenceService: PersistenceService
private applicationEventObserver: EventObserverInterface
private toastService: ToastServiceInterface
constructor(public application: WebApplication, private device: WebOrDesktopDeviceInterface) {
this.eventBus = new InternalEventBus()
@@ -146,6 +147,8 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
this.historyModalController = new HistoryModalController(this.application, this.eventBus)
this.toastService = new ToastService()
this.applicationEventObserver = new ApplicationEventObserver(
application.routeService,
this.purchaseFlowController,
@@ -154,6 +157,8 @@ export class ViewControllerManager implements InternalEventHandlerInterface {
this.syncStatusController,
application.sync,
application.sessions,
application.subscriptions,
this.toastService,
)
this.addAppEventObserver()
@@ -2,17 +2,30 @@
* @jest-environment jsdom
*/
import { RouteServiceInterface, RouteType } from '@standardnotes/ui-services'
import { ApplicationEvent, SessionsClientInterface, SyncClientInterface, SyncOpStatus, User } from '@standardnotes/snjs'
import {
RootQueryParam,
RouteServiceInterface,
RouteParserInterface,
RouteType,
ToastServiceInterface,
} from '@standardnotes/ui-services'
import { ToastType } from '@standardnotes/toast'
import {
ApplicationEvent,
SessionsClientInterface,
SubscriptionClientInterface,
SyncClientInterface,
SyncOpStatus,
User,
} from '@standardnotes/snjs'
import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController'
import { PreferencesController } from '@/Controllers/PreferencesController'
import { PurchaseFlowController } from '@/Controllers/PurchaseFlow/PurchaseFlowController'
import { SyncStatusController } from '@/Controllers/SyncStatusController'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
import { ApplicationEventObserver } from './ApplicationEventObserver'
import { RouteParserInterface } from '@standardnotes/ui-services/dist/Route/RouteParserInterface'
import { AccountMenuPane } from '@/Components/AccountMenu/AccountMenuPane'
describe('ApplicationEventObserver', () => {
let routeService: RouteServiceInterface
@@ -22,6 +35,8 @@ describe('ApplicationEventObserver', () => {
let syncStatusController: SyncStatusController
let syncClient: SyncClientInterface
let sessionManager: SessionsClientInterface
let subscriptionManager: SubscriptionClientInterface
let toastService: ToastServiceInterface
const createObserver = () =>
new ApplicationEventObserver(
@@ -32,6 +47,8 @@ describe('ApplicationEventObserver', () => {
syncStatusController,
syncClient,
sessionManager,
subscriptionManager,
toastService,
)
beforeEach(() => {
@@ -39,6 +56,7 @@ describe('ApplicationEventObserver', () => {
routeService.getRoute = jest.fn().mockReturnValue({
type: RouteType.None,
} as jest.Mocked<RouteParserInterface>)
routeService.removeQueryParameterFromURL = jest.fn()
purchaseFlowController = {} as jest.Mocked<PurchaseFlowController>
purchaseFlowController.openPurchaseFlow = jest.fn()
@@ -59,6 +77,12 @@ describe('ApplicationEventObserver', () => {
sessionManager = {} as jest.Mocked<SessionsClientInterface>
sessionManager.getUser = jest.fn().mockReturnValue({} as jest.Mocked<User>)
subscriptionManager = {} as jest.Mocked<SubscriptionClientInterface>
subscriptionManager.acceptInvitation = jest.fn()
toastService = {} as jest.Mocked<ToastServiceInterface>
toastService.showToast = jest.fn()
})
describe('Upon Application Launched', () => {
@@ -102,6 +126,59 @@ describe('ApplicationEventObserver', () => {
expect(preferencesController.openPreferences).not.toHaveBeenCalled()
expect(preferencesController.setCurrentPane).not.toHaveBeenCalled()
})
it('should open up sign in if user is not logged in and to accept subscription invitation', async () => {
sessionManager.getUser = jest.fn().mockReturnValue(undefined)
routeService.getRoute = jest.fn().mockReturnValue({
type: RouteType.AcceptSubscriptionInvite,
subscriptionInviteParams: {
inviteUuid: '1-2-3',
},
} as jest.Mocked<RouteParserInterface>)
await createObserver().handle(ApplicationEvent.Launched)
expect(accountMenuController.setShow).toHaveBeenCalledWith(true)
expect(accountMenuController.setCurrentPane).toHaveBeenCalledWith(AccountMenuPane.SignIn)
expect(subscriptionManager.acceptInvitation).not.toHaveBeenCalled()
expect(toastService.showToast).not.toHaveBeenCalled()
})
it('should accept subscription invitation if user is logged in', async () => {
subscriptionManager.acceptInvitation = jest.fn().mockReturnValue({ success: true })
routeService.getRoute = jest.fn().mockReturnValue({
type: RouteType.AcceptSubscriptionInvite,
subscriptionInviteParams: {
inviteUuid: '1-2-3',
},
} as jest.Mocked<RouteParserInterface>)
await createObserver().handle(ApplicationEvent.Launched)
expect(subscriptionManager.acceptInvitation).toHaveBeenCalledWith('1-2-3')
expect(toastService.showToast).toHaveBeenCalledWith(
ToastType.Success,
'Successfully joined a shared subscription',
)
expect(routeService.removeQueryParameterFromURL).toHaveBeenCalledWith(RootQueryParam.AcceptSubscriptionInvite)
})
it('should show accept subscription invitation failure if user is logged in and accepting fails', async () => {
subscriptionManager.acceptInvitation = jest.fn().mockReturnValue({ success: false, message: 'Oops!' })
routeService.getRoute = jest.fn().mockReturnValue({
type: RouteType.AcceptSubscriptionInvite,
subscriptionInviteParams: {
inviteUuid: '1-2-3',
},
} as jest.Mocked<RouteParserInterface>)
await createObserver().handle(ApplicationEvent.Launched)
expect(subscriptionManager.acceptInvitation).toHaveBeenCalledWith('1-2-3')
expect(toastService.showToast).toHaveBeenCalledWith(ToastType.Error, 'Oops!')
expect(routeService.removeQueryParameterFromURL).toHaveBeenCalledWith(RootQueryParam.AcceptSubscriptionInvite)
})
})
describe('Upon Signing In', () => {
@@ -118,6 +195,25 @@ describe('ApplicationEventObserver', () => {
expect(preferencesController.openPreferences).toHaveBeenCalled()
expect(preferencesController.setCurrentPane).toHaveBeenCalledWith('general')
})
it('should accept subscription invitation', async () => {
subscriptionManager.acceptInvitation = jest.fn().mockReturnValue({ success: true })
routeService.getRoute = jest.fn().mockReturnValue({
type: RouteType.AcceptSubscriptionInvite,
subscriptionInviteParams: {
inviteUuid: '1-2-3',
},
} as jest.Mocked<RouteParserInterface>)
await createObserver().handle(ApplicationEvent.SignedIn)
expect(subscriptionManager.acceptInvitation).toHaveBeenCalledWith('1-2-3')
expect(toastService.showToast).toHaveBeenCalledWith(
ToastType.Success,
'Successfully joined a shared subscription',
)
expect(routeService.removeQueryParameterFromURL).toHaveBeenCalledWith(RootQueryParam.AcceptSubscriptionInvite)
})
})
describe('Upon Sync Status Changing', () => {
@@ -1,5 +1,17 @@
import { RouteServiceInterface, RouteType } from '@standardnotes/ui-services'
import { ApplicationEvent, SessionsClientInterface, SyncClientInterface } from '@standardnotes/snjs'
import {
RootQueryParam,
RouteParserInterface,
RouteServiceInterface,
RouteType,
ToastServiceInterface,
} from '@standardnotes/ui-services'
import {
ApplicationEvent,
SessionsClientInterface,
SubscriptionClientInterface,
SyncClientInterface,
} from '@standardnotes/snjs'
import { ToastType } from '@standardnotes/toast'
import { PurchaseFlowController } from '@/Controllers/PurchaseFlow/PurchaseFlowController'
import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController'
@@ -18,6 +30,8 @@ export class ApplicationEventObserver implements EventObserverInterface {
private syncStatusController: SyncStatusController,
private syncClient: SyncClientInterface,
private sessionManager: SessionsClientInterface,
private subscriptionManager: SubscriptionClientInterface,
private toastService: ToastServiceInterface,
) {}
async handle(event: ApplicationEvent): Promise<void> {
@@ -33,8 +47,7 @@ export class ApplicationEventObserver implements EventObserverInterface {
case RouteType.Settings: {
const user = this.sessionManager.getUser()
if (user === undefined) {
this.accountMenuController.setShow(true)
this.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
this.promptUserSignIn()
break
}
@@ -43,6 +56,17 @@ export class ApplicationEventObserver implements EventObserverInterface {
this.preferencesController.setCurrentPane(route.settingsParams.panel)
break
}
case RouteType.AcceptSubscriptionInvite: {
const user = this.sessionManager.getUser()
if (user === undefined) {
this.promptUserSignIn()
break
}
await this.acceptSubscriptionInvitation(route)
break
}
}
}
break
@@ -54,6 +78,10 @@ export class ApplicationEventObserver implements EventObserverInterface {
this.preferencesController.openPreferences()
this.preferencesController.setCurrentPane(route.settingsParams.panel)
break
case RouteType.AcceptSubscriptionInvite:
await this.acceptSubscriptionInvitation(route)
break
}
}
@@ -63,4 +91,20 @@ export class ApplicationEventObserver implements EventObserverInterface {
break
}
}
private promptUserSignIn(): void {
this.accountMenuController.setShow(true)
this.accountMenuController.setCurrentPane(AccountMenuPane.SignIn)
}
private async acceptSubscriptionInvitation(route: RouteParserInterface): Promise<void> {
const acceptResult = await this.subscriptionManager.acceptInvitation(route.subscriptionInviteParams.inviteUuid)
const toastType = acceptResult.success ? ToastType.Success : ToastType.Error
const toastMessage = acceptResult.success ? 'Successfully joined a shared subscription' : acceptResult.message
this.toastService.showToast(toastType, toastMessage)
this.routeService.removeQueryParameterFromURL(RootQueryParam.AcceptSubscriptionInvite)
}
}
@@ -1,27 +1,24 @@
import { KeyboardKey } from '@standardnotes/ui-services'
import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants'
import { useCallback, useState, useEffect, RefObject } from 'react'
import { useCallback, useEffect, RefObject, useRef } from 'react'
export const useListKeyboardNavigation = (container: RefObject<HTMLElement | null>, initialFocus = 0) => {
const [listItems, setListItems] = useState<HTMLButtonElement[]>()
const [focusedItemIndex, setFocusedItemIndex] = useState<number>(initialFocus)
const listItems = useRef<HTMLButtonElement[]>([])
const focusedItemIndex = useRef<number>(initialFocus)
const focusItemWithIndex = useCallback(
(index: number, items?: HTMLButtonElement[]) => {
setFocusedItemIndex(index)
if (items && items.length > 0) {
items[index]?.focus()
} else {
listItems?.[index]?.focus()
}
},
[listItems],
)
const focusItemWithIndex = useCallback((index: number, items?: HTMLButtonElement[]) => {
focusedItemIndex.current = index
if (items && items.length > 0) {
items[index]?.focus()
} else {
listItems.current[index]?.focus()
}
}, [])
useEffect(() => {
if (container.current) {
container.current.tabIndex = FOCUSABLE_BUT_NOT_TABBABLE
setListItems(Array.from(container.current.querySelectorAll('button')))
listItems.current = Array.from(container.current.querySelectorAll('button'))
}
}, [container])
@@ -33,47 +30,44 @@ export const useListKeyboardNavigation = (container: RefObject<HTMLElement | nul
return
}
if (!listItems?.length) {
setListItems(Array.from(container.current?.querySelectorAll('button') as NodeListOf<HTMLButtonElement>))
listItems.current = Array.from(container.current?.querySelectorAll('button') as NodeListOf<HTMLButtonElement>)
if (e.key === KeyboardKey.Up) {
let previousIndex = focusedItemIndex.current - 1
if (previousIndex < 0) {
previousIndex = listItems.current.length - 1
}
focusItemWithIndex(previousIndex)
}
if (listItems) {
if (e.key === KeyboardKey.Up) {
let previousIndex = focusedItemIndex - 1
if (previousIndex < 0) {
previousIndex = listItems.length - 1
}
focusItemWithIndex(previousIndex)
}
if (e.key === KeyboardKey.Down) {
let nextIndex = focusedItemIndex + 1
if (nextIndex > listItems.length - 1) {
nextIndex = 0
}
focusItemWithIndex(nextIndex)
if (e.key === KeyboardKey.Down) {
let nextIndex = focusedItemIndex.current + 1
if (nextIndex > listItems.current.length - 1) {
nextIndex = 0
}
focusItemWithIndex(nextIndex)
}
},
[container, focusItemWithIndex, focusedItemIndex, listItems],
[container, focusItemWithIndex],
)
const FIRST_ITEM_FOCUS_TIMEOUT = 20
const containerFocusHandler = useCallback(() => {
let temporaryItems = listItems && listItems?.length > 0 ? listItems : []
if (!temporaryItems.length) {
temporaryItems = Array.from(container.current?.querySelectorAll('button') as NodeListOf<HTMLButtonElement>)
setListItems(temporaryItems)
const items = Array.from(container.current?.querySelectorAll('button') as NodeListOf<HTMLButtonElement>)
listItems.current = items
if (items.length < 1) {
return
}
if (temporaryItems.length > 0) {
const selectedItemIndex = Array.from(temporaryItems).findIndex((item) => item.dataset.selected)
const indexToFocus = selectedItemIndex > -1 ? selectedItemIndex : initialFocus
setTimeout(() => {
focusItemWithIndex(indexToFocus, temporaryItems)
}, FIRST_ITEM_FOCUS_TIMEOUT)
}
}, [container, focusItemWithIndex, initialFocus, listItems])
const selectedItemIndex = Array.from(items).findIndex((item) => item.dataset.selected)
const indexToFocus = selectedItemIndex > -1 ? selectedItemIndex : initialFocus
setTimeout(() => {
focusItemWithIndex(indexToFocus, items)
}, FIRST_ITEM_FOCUS_TIMEOUT)
}, [container, focusItemWithIndex, initialFocus])
useEffect(() => {
const containerElement = container.current
@@ -112,11 +112,16 @@
}
.content-list-item {
&.selected,
&:hover {
&.selected {
background-color: var(--item-cell-selected-background-color);
}
@media screen and (hover: hover) {
&:hover {
background-color: var(--item-cell-selected-background-color);
}
}
ul {
list-style: disc;
}
+1
View File
@@ -2,6 +2,7 @@
"extends": "../../node_modules/@standardnotes/config/src/tsconfig.json",
"compilerOptions": {
"skipLibCheck": true,
"lib": ["ES2022"],
"target": "ES2019",
"module": "commonjs",
"moduleResolution": "node",
+794 -10
View File
File diff suppressed because it is too large Load Diff