WIP model
This commit is contained in:
@@ -143,6 +143,7 @@
|
||||
"expo-updates": "~0.25.14",
|
||||
"expo-web-browser": "~13.0.3",
|
||||
"fast-text-encoding": "^1.0.6",
|
||||
"fuse.js": "^7.0.0",
|
||||
"history": "^5.3.0",
|
||||
"hls.js": "^1.5.11",
|
||||
"js-sha256": "^0.9.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {MMKV} from 'react-native-mmkv'
|
||||
|
||||
import {IS_DEV} from '#/env'
|
||||
import {Device} from '#/storage/schema'
|
||||
import {Account} from '#/storage/schema'
|
||||
|
||||
export * from '#/storage/schema'
|
||||
|
||||
@@ -74,6 +74,13 @@ export class Storage<Scopes extends unknown[], Schema> {
|
||||
*/
|
||||
export const device = new Storage<[], Device>({id: 'bsky_device'})
|
||||
|
||||
/**
|
||||
* Account data that's specific to the account
|
||||
*
|
||||
* `account.set([did, key], true)`
|
||||
*/
|
||||
export const account = new Storage<[string], Account>({id: 'bsky_account'})
|
||||
|
||||
if (IS_DEV && typeof window !== 'undefined') {
|
||||
// @ts-ignore
|
||||
window.bsky_storage = {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {Result} from '#/view/com/composer/text-input/tagsAutocompleteState'
|
||||
|
||||
/**
|
||||
* Device data that's specific to the device and does not vary based account
|
||||
*/
|
||||
@@ -9,3 +11,10 @@ export type Device = {
|
||||
countryCode: string | undefined
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Account data that's specific to the current account
|
||||
*/
|
||||
export type Account = {
|
||||
recentTags: Result[] | undefined
|
||||
}
|
||||
|
||||
@@ -13,15 +13,17 @@ import {Text as TiptapText} from '@tiptap/extension-text'
|
||||
import {generateJSON} from '@tiptap/html'
|
||||
import {EditorContent, JSONContent, useEditor} from '@tiptap/react'
|
||||
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {blobToDataUri, isUriImage} from '#/lib/media/util'
|
||||
import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
|
||||
import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle'
|
||||
import {blobToDataUri, isUriImage} from 'lib/media/util'
|
||||
import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
|
||||
import {useSession} from '#/state/session'
|
||||
import {tagAutocompleteModel} from '#/view/com/composer/text-input/tagsAutocompleteState'
|
||||
import {
|
||||
LinkFacetMatch,
|
||||
suggestLinkCardUri,
|
||||
} from 'view/com/composer/text-input/text-input-util'
|
||||
} from '#/view/com/composer/text-input/text-input-util'
|
||||
import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
|
||||
import {atoms as a, useAlf} from '#/alf'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {normalizeTextStyles} from '#/components/Typography'
|
||||
@@ -29,8 +31,7 @@ import {Text} from '../../util/text/Text'
|
||||
import {createSuggestion} from './web/Autocomplete'
|
||||
import {Emoji} from './web/EmojiPicker.web'
|
||||
import {LinkDecorator} from './web/LinkDecorator'
|
||||
import {TagDecorator} from './web/TagDecorator'
|
||||
import {Tags, createTagsAutocomplete} from './web/Tags'
|
||||
import {createTagsAutocomplete,Tags} from './web/Tags'
|
||||
|
||||
export interface TextInputRef {
|
||||
focus: () => void
|
||||
@@ -65,6 +66,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
||||
const autocomplete = useActorAutocompleteFn()
|
||||
const pal = usePalette('default')
|
||||
const modeClass = useColorSchemeStyle('ProseMirror-light', 'ProseMirror-dark')
|
||||
const {currentAccount} = useSession()
|
||||
|
||||
const [isDropping, setIsDropping] = React.useState(false)
|
||||
|
||||
@@ -78,6 +80,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
||||
class: 'inline-tag',
|
||||
},
|
||||
suggestion: createTagsAutocomplete({
|
||||
model: tagAutocompleteModel({currentDid: currentAccount?.did!}),
|
||||
}),
|
||||
}),
|
||||
Mention.configure({
|
||||
@@ -94,7 +97,7 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
||||
History,
|
||||
Hardbreak,
|
||||
],
|
||||
[autocomplete, placeholder],
|
||||
[autocomplete, placeholder, currentAccount],
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import {account} from '#/storage'
|
||||
|
||||
export type Result = {
|
||||
value: string
|
||||
}
|
||||
|
||||
export type Model = {
|
||||
search(query: string): Promise<Result[]>
|
||||
save(tag: string): void
|
||||
}
|
||||
|
||||
export function tagAutocompleteModel({
|
||||
currentDid,
|
||||
}: {
|
||||
currentDid: string
|
||||
}): Model {
|
||||
let recentTags = account.get([currentDid, 'recentTags']) || []
|
||||
|
||||
return {
|
||||
async search(query: string) {
|
||||
if (!query) return [{value: query}]
|
||||
return [{value: query}]
|
||||
},
|
||||
save(tag: string) {
|
||||
recentTags = [
|
||||
{value: tag},
|
||||
...recentTags.filter(t => t.value !== tag),
|
||||
].slice(0, 40)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -9,28 +9,32 @@ import {
|
||||
import tippy, {Instance as TippyInstance} from 'tippy.js'
|
||||
|
||||
// import {TagsAutocompleteModel} from 'state/models/ui/tags-autocomplete'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {
|
||||
Model,
|
||||
Result,
|
||||
} from '#/view/com/composer/text-input/tagsAutocompleteState'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {parsePunctuationFromTag} from './utils'
|
||||
|
||||
type AutocompleteResult = string
|
||||
type ListProps = SuggestionProps<AutocompleteResult> & {
|
||||
// autocompleteModel: TagsAutocompleteModel
|
||||
type ListProps = SuggestionProps<Result> & {
|
||||
model: Model
|
||||
}
|
||||
type AutocompleteRef = {
|
||||
onKeyDown: (props: SuggestionKeyDownProps) => boolean
|
||||
}
|
||||
|
||||
export function createTagsAutocomplete({}: // autocompleteModel,
|
||||
{
|
||||
// autocompleteModel: TagsAutocompleteModel
|
||||
export function createTagsAutocomplete({
|
||||
model,
|
||||
}: {
|
||||
model: Model
|
||||
}): Omit<SuggestionOptions, 'editor'> {
|
||||
return {
|
||||
/**
|
||||
* This `query` param comes from the result of `findSuggestionMatch`
|
||||
*/
|
||||
async items({query}) {
|
||||
return [query, 'javascript']
|
||||
return await model.search(query)
|
||||
},
|
||||
render() {
|
||||
let component: ReactRenderer<AutocompleteRef> | undefined
|
||||
@@ -41,6 +45,7 @@ export function createTagsAutocomplete({}: // autocompleteModel,
|
||||
component = new ReactRenderer(Autocomplete, {
|
||||
props: {
|
||||
...props,
|
||||
model,
|
||||
},
|
||||
editor: props.editor,
|
||||
})
|
||||
@@ -113,7 +118,7 @@ const Autocomplete = forwardRef<AutocompleteRef, ListProps>(
|
||||
const selectItem = React.useCallback(
|
||||
(index: number) => {
|
||||
const item = items[index]
|
||||
if (item) commit(item)
|
||||
if (item) commit(item.value)
|
||||
},
|
||||
[items, commit],
|
||||
)
|
||||
@@ -157,7 +162,8 @@ const Autocomplete = forwardRef<AutocompleteRef, ListProps>(
|
||||
return (
|
||||
<div className="items">
|
||||
<View style={[pal.borderDark, pal.view, styles.container]}>
|
||||
{items.map((tag, index) => {
|
||||
{items.map(({value}, index) => {
|
||||
const {tag} = parsePunctuationFromTag(value)
|
||||
const isSelected = selectedIndex === index
|
||||
const isFirst = index === 0
|
||||
const isLast = index === items.length - 1
|
||||
|
||||
@@ -12153,6 +12153,11 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3:
|
||||
resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
|
||||
integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
|
||||
|
||||
fuse.js@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.0.0.tgz#6573c9fcd4c8268e403b4fc7d7131ffcf99a9eb2"
|
||||
integrity sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==
|
||||
|
||||
gensync@^1.0.0-beta.2:
|
||||
version "1.0.0-beta.2"
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
|
||||
Reference in New Issue
Block a user