Use api package regexes
This commit is contained in:
@@ -1,10 +1,3 @@
|
|||||||
export const TAG_REGEX =
|
|
||||||
/(?:^|\s)(#[\p{L}\p{Emoji_Presentation}\p{Emoji_Modifier_Base}\p{Extended_Pictographic}]{1}[\p{L}\p{Emoji_Presentation}\p{Emoji_Modifier_Base}\p{Extended_Pictographic}\d_-]*)/giu
|
|
||||||
export const LOOSE_TAG_REGEX =
|
|
||||||
/(?:^|\s)(#[\p{L}\p{Emoji_Presentation}\p{Emoji_Modifier_Base}\p{Extended_Pictographic}]{1}[\p{L}\p{Emoji_Presentation}\p{Emoji_Modifier_Base}\p{Extended_Pictographic}\d_-]*\S*)/giu
|
|
||||||
export const ENDING_PUNCTUATION_REGEX = /\p{P}+$/gu
|
|
||||||
export const LEADING_HASH_REGEX = /^#/g
|
|
||||||
|
|
||||||
export function sanitize(tagString: string) {
|
export function sanitize(tagString: string) {
|
||||||
return tagString
|
return tagString
|
||||||
.trim()
|
.trim()
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class TagsAutocompleteModel {
|
|||||||
isActive = false
|
isActive = false
|
||||||
query = ''
|
query = ''
|
||||||
searchedTags: string[] = []
|
searchedTags: string[] = []
|
||||||
profileTags: string[] = ['biology']
|
profileTags: string[] = []
|
||||||
|
|
||||||
constructor(public rootStore: RootStoreModel) {
|
constructor(public rootStore: RootStoreModel) {
|
||||||
makeAutoObservable(
|
makeAutoObservable(
|
||||||
@@ -113,15 +113,7 @@ export class TagsAutocompleteModel {
|
|||||||
// TODO hook up to search type-ahead
|
// TODO hook up to search type-ahead
|
||||||
async _search() {
|
async _search() {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.searchedTags = [
|
this.searchedTags = []
|
||||||
'bluesky',
|
|
||||||
'code',
|
|
||||||
'coding',
|
|
||||||
'dev',
|
|
||||||
'developer',
|
|
||||||
'development',
|
|
||||||
'devlife',
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import * as Sheet from 'view/com/sheets/Base'
|
|||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {ActivityIndicator} from 'react-native'
|
import {ActivityIndicator} from 'react-native'
|
||||||
import {TagInputEntryButton} from './TagInputEntryButton'
|
import {TagInputEntryButton} from './TagInputEntryButton'
|
||||||
import {sanitize} from 'lib/strings/hashtags'
|
|
||||||
import {uniq} from 'lib/strings/helpers'
|
import {uniq} from 'lib/strings/helpers'
|
||||||
|
import {sanitizeHashtag} from './util'
|
||||||
|
|
||||||
export function TagInput({
|
export function TagInput({
|
||||||
max = 8,
|
max = 8,
|
||||||
@@ -70,7 +70,7 @@ export function TagInput({
|
|||||||
|
|
||||||
const addTagAndReset = React.useCallback(
|
const addTagAndReset = React.useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
const tag = sanitize(value)
|
const tag = sanitizeHashtag(value)
|
||||||
|
|
||||||
// enforce max hashtag length
|
// enforce max hashtag length
|
||||||
if (tag.length > 0 && tag.length <= 64) {
|
if (tag.length > 0 && tag.length <= 64) {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import {Text} from 'view/com/util/text/Text'
|
|||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {TagInputEntryButton} from './TagInputEntryButton'
|
import {TagInputEntryButton} from './TagInputEntryButton'
|
||||||
import {TextInputFocusEventData} from 'react-native'
|
import {TextInputFocusEventData} from 'react-native'
|
||||||
import {sanitize} from 'lib/strings/hashtags'
|
|
||||||
import {uniq} from 'lib/strings/helpers'
|
import {uniq} from 'lib/strings/helpers'
|
||||||
|
import {sanitizeHashtag} from './util'
|
||||||
|
|
||||||
export function TagInput({
|
export function TagInput({
|
||||||
max = 8,
|
max = 8,
|
||||||
@@ -84,7 +84,7 @@ export function TagInput({
|
|||||||
|
|
||||||
const addTagAndReset = React.useCallback(
|
const addTagAndReset = React.useCallback(
|
||||||
(value: string) => {
|
(value: string) => {
|
||||||
const tag = sanitize(value)
|
const tag = sanitizeHashtag(value)
|
||||||
|
|
||||||
// enforce max hashtag length
|
// enforce max hashtag length
|
||||||
if (tag.length > 0 && tag.length <= 64) {
|
if (tag.length > 0 && tag.length <= 64) {
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import {TRAILING_PUNCTUATION_REGEX, LEADING_HASH_REGEX} from '@atproto/api'
|
||||||
|
|
||||||
|
export function sanitizeHashtag(tagString: string) {
|
||||||
|
return tagString
|
||||||
|
.trim()
|
||||||
|
.replace(LEADING_HASH_REGEX, '')
|
||||||
|
.replace(TRAILING_PUNCTUATION_REGEX, '')
|
||||||
|
}
|
||||||
@@ -5,13 +5,13 @@ import {TagsAutocompleteModel} from 'state/models/ui/tags-autocomplete'
|
|||||||
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
import {useAnimatedValue} from 'lib/hooks/useAnimatedValue'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {LEADING_HASH_REGEX, TAG_REGEX} from 'lib/strings/hashtags'
|
import {LEADING_HASH_REGEX, HASHTAG_REGEX} from '@atproto/api'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loops over matches in the text to find the hashtag under the cursor.
|
* Loops over matches in the text to find the hashtag under the cursor.
|
||||||
*/
|
*/
|
||||||
export function getHashtagAt(text: string, position: number) {
|
export function getHashtagAt(text: string, position: number) {
|
||||||
for (const match of Array.from(text.matchAll(TAG_REGEX))) {
|
for (const match of Array.from(text.matchAll(HASHTAG_REGEX))) {
|
||||||
const {index} = match
|
const {index} = match
|
||||||
const [matchedString, tag] = match
|
const [matchedString, tag] = match
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import {
|
import {
|
||||||
LOOSE_TAG_REGEX,
|
HASHTAG_REGEX_WITH_TRAILING_PUNCTUATION,
|
||||||
ENDING_PUNCTUATION_REGEX,
|
TRAILING_PUNCTUATION_REGEX,
|
||||||
LEADING_HASH_REGEX,
|
LEADING_HASH_REGEX,
|
||||||
} from 'lib/strings/hashtags'
|
} from '@atproto/api'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method eventually receives the `query` property from the result of
|
||||||
|
* `findSuggestionMatch` below.
|
||||||
|
*/
|
||||||
export function parsePunctuationFromTag(value: string) {
|
export function parsePunctuationFromTag(value: string) {
|
||||||
const reg = ENDING_PUNCTUATION_REGEX
|
const reg = TRAILING_PUNCTUATION_REGEX
|
||||||
const tag = value.replace(reg, '')
|
const tag = value.replace(reg, '')
|
||||||
const punctuation = value.match(reg)?.[0] || ''
|
const punctuation = value.match(reg)?.[0] || ''
|
||||||
|
|
||||||
@@ -26,25 +30,27 @@ export function findSuggestionMatch({
|
|||||||
text: string
|
text: string
|
||||||
cursorPosition: number
|
cursorPosition: number
|
||||||
}) {
|
}) {
|
||||||
const match = Array.from(text.matchAll(LOOSE_TAG_REGEX)).pop()
|
const match = Array.from(
|
||||||
|
text.matchAll(HASHTAG_REGEX_WITH_TRAILING_PUNCTUATION),
|
||||||
|
).pop()
|
||||||
|
|
||||||
if (!match || match.input === undefined || match.index === undefined) {
|
if (!match || match.input === undefined || match.index === undefined) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const startIndex = cursorPosition - text.length
|
const startIndex = cursorPosition - text.length
|
||||||
let [matchedString, looselyMatchedTag] = match
|
let [matchedString, tagWithTrailingPunctuation] = match
|
||||||
|
|
||||||
const sanitized = looselyMatchedTag
|
const sanitized = tagWithTrailingPunctuation
|
||||||
.replace(ENDING_PUNCTUATION_REGEX, '')
|
.replace(TRAILING_PUNCTUATION_REGEX, '')
|
||||||
.replace(LEADING_HASH_REGEX, '')
|
.replace(LEADING_HASH_REGEX, '')
|
||||||
|
|
||||||
// one of our hashtag spec rules
|
// one of our hashtag spec rules
|
||||||
if (sanitized.length > 64) return null
|
if (sanitized.length > 64) return null
|
||||||
|
|
||||||
const from =
|
const from =
|
||||||
startIndex + match.index + matchedString.indexOf(looselyMatchedTag)
|
startIndex + match.index + matchedString.indexOf(tagWithTrailingPunctuation)
|
||||||
const to = from + looselyMatchedTag.length
|
const to = from + tagWithTrailingPunctuation.length
|
||||||
|
|
||||||
if (from < cursorPosition && to >= cursorPosition) {
|
if (from < cursorPosition && to >= cursorPosition) {
|
||||||
return {
|
return {
|
||||||
@@ -58,7 +64,7 @@ export function findSuggestionMatch({
|
|||||||
*
|
*
|
||||||
* We parse out the punctuation later.
|
* We parse out the punctuation later.
|
||||||
*/
|
*/
|
||||||
query: looselyMatchedTag.replace(LEADING_HASH_REGEX, ''),
|
query: tagWithTrailingPunctuation.replace(LEADING_HASH_REGEX, ''),
|
||||||
// raw text string
|
// raw text string
|
||||||
text: matchedString,
|
text: matchedString,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user