mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
refactor: support path mode in Safari
This commit is contained in:
parent
1bcdc4dae2
commit
7dd0f4d191
4 changed files with 42 additions and 32 deletions
|
|
@ -1,18 +1,23 @@
|
|||
import * as React from 'react'
|
||||
|
||||
export function Highlight(props: { text: string; match?: RegExp }) {
|
||||
export function Highlight(props: { text: string; match?: RegExp | string }) {
|
||||
const { text, match } = props
|
||||
const $match = React.useMemo(() => {
|
||||
if (match instanceof RegExp) {
|
||||
if (match.flags.includes('g')) return match
|
||||
return new RegExp(match.source, 'g' + match.flags)
|
||||
if (match) {
|
||||
if (match instanceof RegExp) {
|
||||
if (match.flags.includes('g')) return match
|
||||
return new RegExp(match.source, 'g' + match.flags)
|
||||
}
|
||||
return new RegExp(match, 'g')
|
||||
}
|
||||
return null
|
||||
}, [match])
|
||||
|
||||
if (!($match instanceof RegExp) || typeof text !== 'string') return <>{text}</>
|
||||
if (!$match) return <>{text}</>
|
||||
|
||||
const matchedPieces = Array.from(text.matchAll($match)).map(([text]) => text)
|
||||
const matchedPieces = Array.from(text.matchAll($match)).map(
|
||||
([text, highlightText = text]) => highlightText,
|
||||
)
|
||||
const preservedPieces = text.split($match)
|
||||
const content = []
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import * as React from 'react'
|
|||
import { cx } from 'utils/cx'
|
||||
import { hasUpperCase } from 'utils/general'
|
||||
import { ModeShape } from '.'
|
||||
import { Highlight } from '../Highlight'
|
||||
|
||||
export const fuzzyMode: ModeShape = {
|
||||
getSearchParams(searchKey) {
|
||||
|
|
@ -26,13 +25,13 @@ export const fuzzyMode: ModeShape = {
|
|||
let progress = 0
|
||||
return chunks.map((chunk, index, chunks) => {
|
||||
const chunkIndexes = indexes.filter(i => i >= progress && i < chunk.length + progress)
|
||||
const regexp = chunkIndexes.length
|
||||
? new RegExp(chunkIndexes.map(i => `(?<=^.{${i - progress}}).`).join('|'))
|
||||
: undefined
|
||||
|
||||
const $indexes = chunkIndexes.length ? chunkIndexes.map(i => i - progress) : undefined
|
||||
|
||||
progress += chunk.length + 1
|
||||
return (
|
||||
<span key={chunk} className={cx({ prefix: index + 1 !== chunks.length })}>
|
||||
<Highlight match={regexp} text={index + 1 === chunks.length ? chunk : chunk + '/'} />
|
||||
<Highlight match={$indexes} text={index + 1 === chunks.length ? chunk : chunk + '/'} />
|
||||
</span>
|
||||
)
|
||||
})
|
||||
|
|
@ -61,3 +60,19 @@ function fuzzyMatchIndexes(input: string, sample: string, shift: number = 0) {
|
|||
}
|
||||
return indexes
|
||||
}
|
||||
|
||||
function Highlight(props: { text: string; match?: number[] }) {
|
||||
const { text, match } = props
|
||||
|
||||
if (!match?.length) return <>{text}</>
|
||||
|
||||
return (
|
||||
<>
|
||||
{text
|
||||
.split('')
|
||||
.map((char, i) =>
|
||||
match.includes(i) ? <mark key={i}>{char}</mark> : <span key={i}>{char}</span>,
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,22 @@
|
|||
import * as React from 'react'
|
||||
import { cx } from 'utils/cx'
|
||||
import { hasUpperCase, isValidRegexpSource, searchKeyToRegexp } from 'utils/general'
|
||||
import { searchKeyToRegexp } from 'utils/general'
|
||||
import { ModeShape } from '.'
|
||||
import { Highlight } from '../Highlight'
|
||||
|
||||
export const regexMode: ModeShape = {
|
||||
getSearchParams(searchKey) {
|
||||
if (!searchKey) return null
|
||||
|
||||
const regexp = searchKeyToRegexp(searchKey)
|
||||
if (regexp) {
|
||||
const matchNode = (node: TreeNode) => regexp.test(node.name)
|
||||
|
||||
return {
|
||||
matchNode,
|
||||
matchNode: node => regexp.test(node.name),
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
renderNodeLabelText(node, searchKey) {
|
||||
const regex =
|
||||
searchKey && isValidRegexpSource(searchKey)
|
||||
? new RegExp(searchKey, 'g' + (hasUpperCase(searchKey) ? '' : 'i'))
|
||||
: undefined
|
||||
const regex = searchKeyToRegexp(searchKey) || undefined
|
||||
const { name } = node
|
||||
return name.includes('/') ? (
|
||||
name.split('/').map((chunk, index, chunks) => (
|
||||
|
|
|
|||
|
|
@ -146,13 +146,7 @@ export async function JSONRequest(url: string, data: any, extra: RequestInit = {
|
|||
export function searchKeyToRegexp(searchKey: string) {
|
||||
if (!searchKey) return null
|
||||
|
||||
try {
|
||||
const flags = hasUpperCase(searchKey) ? '' : 'i'
|
||||
// case-sensitive when searchKey contains uppercase char
|
||||
return new RegExp(searchKey, flags)
|
||||
} catch (err) {
|
||||
return null // matching nothing if failed transforming regexp
|
||||
}
|
||||
return safeRegexp(searchKey, hasUpperCase(searchKey) ? 'g' : 'gi')
|
||||
}
|
||||
|
||||
export function hasUpperCase(input: string) {
|
||||
|
|
@ -168,15 +162,18 @@ export async function renderReact(element: ReactElement) {
|
|||
})
|
||||
}
|
||||
|
||||
export function isValidRegexpSource(source: string) {
|
||||
export function safeRegexp(pattern: string | RegExp, flags?: string | undefined) {
|
||||
try {
|
||||
new RegExp(source)
|
||||
return true
|
||||
return new RegExp(pattern, flags)
|
||||
} catch (err) {
|
||||
return false
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function isValidRegexpSource(source: string) {
|
||||
return Boolean(safeRegexp(source))
|
||||
}
|
||||
|
||||
export function withEffect<Method extends (...args: any[]) => any>(
|
||||
method: Method,
|
||||
effect: (payload: ReturnType<Method>) => void,
|
||||
|
|
|
|||
Loading…
Reference in a new issue