Skip to content

Commit

Permalink
Version 0.0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
FIameCaster committed Aug 11, 2023
1 parent 4192f71 commit b5d4f21
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 53 deletions.
2 changes: 1 addition & 1 deletion package/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prism-code-editor",
"version": "0.0.4",
"version": "0.0.5",
"type": "module",
"description": "Lightweight, extensible code editor for the web using Prism",
"main": "./dist/index.js",
Expand Down
11 changes: 3 additions & 8 deletions package/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ const createEditor = (

scrollContainer.style.tabSize = <any>currentOptions.tabSize || 2
if (isNewGrammar || value != textarea.value) {
focusRelatedTarget()
// Safari focuses the textarea if you change its selection or value programmatically
if (isWebKit && !focused())
addTextareaListener("focus", e => (<HTMLElement>e.relatedTarget)?.focus(), { once: true })
textarea.value = value
textarea.selectionEnd = 0
update()
Expand Down Expand Up @@ -179,12 +181,6 @@ const createEditor = (

const inputCommandMap: Record<string, InputCommandCallback | null> = {}

// Safari focuses the textarea if you change its selection or value programmatically
const focusRelatedTarget = () =>
isWebKit &&
!focused() &&
addTextareaListener("focus", e => (<HTMLElement>e.relatedTarget)?.focus(), { once: true })

const dispatchEvent = <T extends keyof EditorEventMap>(
name: T,
...args: Parameters<EditorEventMap[T]>
Expand Down Expand Up @@ -225,7 +221,6 @@ const createEditor = (
update,
getSelection: getInputSelection,
setSelection(start, end, direction) {
focusRelatedTarget()
textarea.setSelectionRange(start, end ?? start, direction)
dispatchSelection()
},
Expand Down
15 changes: 8 additions & 7 deletions package/src/extensions/search/replace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,22 @@ const createReplaceAPI = (editor: PrismEditor): ReplaceAPI => {

return Object.assign(search, {
next() {
let [start, end] = getSelection(),
const cursor = getSelection()[1],
matches = search.matches,
l = matches.length
if (start == end) end++
for (let i = 0; i < l; i++) {
if (matches[i][0] >= end) return i
for (let i = 0, match: [number, number]; i < l; i++) {
match = matches[i]
if (match[0] - <any>(match[0] == match[1]) >= cursor) return i
}
return l ? 0 : -1
},
prev() {
const caretPos = getSelection()[1],
const cursor = getSelection()[0],
matches = search.matches,
l = matches.length
for (let i = l; i; ) {
if (matches[--i][1] < caretPos) return i
for (let i = l, match: [number, number]; i; ) {
match = matches[--i]
if (match[1] + <any>(match[0] == match[1]) <= cursor) return i
}
return l - 1
},
Expand Down
77 changes: 42 additions & 35 deletions package/src/extensions/search/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { regexEscape, getLines, getModifierCode } from "../../utils"
import { createReplaceAPI } from "./replace"

const template = createTemplate(
'<div class="prism-search"><button aria-expanded="false" title="Toggle Replace" class="expand-search"></button><div spellcheck="false"><div><div class="input find"><input autocorrect="off" autocapitalize="off" placeholder="Find" aria-label="Find"><button class="prev-match" title="Previous Match (Shift+Enter)"></button><button class="next-match" title="Next Match (Enter)"></button><div class="search-error"></div></div><button class="search-close" title="Close (Esc)"></button></div><div class="input replace"><input autocorrect="off" autocapitalize="off" placeholder="Replace" aria-label="Replace"><button title="(Enter)">Replace</button><button title="(Ctrl+Alt+Enter)">All</button></div><div class="search-options"><div class="match-count">0<span> of </span>0</div><button aria-pressed="false" class="use-regexp" title="RegExp Search (Alt+R)"><span aria-hidden="true"></span></button><button aria-pressed="false" title="Match Case (Alt+C)"><span aria-hidden="true">Aa</span></button><button aria-pressed="false" class="whole-word" title="Match Whole Word (Alt+W)"><span aria-hidden="true">ab</span></button><button aria-pressed="false" class="find-in-selection" title="Find in Selection (Alt+L)"></button></div></div></div>',
'<div class="prism-search"><button aria-expanded="false" title="Toggle Replace" class="expand-search"></button><div spellcheck="false"><div><div class="input find"><input autocorrect="off" autocapitalize="off" placeholder="Find" aria-label="Find"><button class="prev-match" title="Previous Match (Shift+Enter)"></button><button class="next-match" title="Next Match (Enter)"></button><div class="search-error"></div></div><button class="search-close" title="Close (Esc)"></button></div><div class="input replace"><input autocorrect="off" autocapitalize="off" placeholder="Replace" aria-label="Replace"><button title="(Enter)">Replace</button><button>All</button></div><div class="search-options"><div class="match-count">0<span> of </span>0</div><button aria-pressed="false" class="use-regexp"><span aria-hidden="true"></span></button><button aria-pressed="false"><span aria-hidden="true">Aa</span></button><button aria-pressed="false" class="whole-word"><span aria-hidden="true">ab</span></button><button aria-pressed="false" class="find-in-selection"></button></div></div></div>',
"display:none;align-items:flex-start;justify-content:flex-end;left:var(--padding-left);",
"prism-search-container",
)
Expand Down Expand Up @@ -125,7 +125,6 @@ export const searchWidget = (): SearchWidget => {
if (end <= searchStart - +(diff < 0)) searchSelection[0] -= diff
}
}
if (selectNext) replaceInput.focus()
startSearch(selectNext)
selectNext = false
}
Expand Down Expand Up @@ -183,25 +182,28 @@ export const searchWidget = (): SearchWidget => {

const observer = window.ResizeObserver ? new ResizeObserver(resize) : null

const replace = () => {
selectNext = true
replaceAPI.replace(replaceInput.value)
}

const replaceAll = () => {
replaceAPI.replaceAll(replaceInput.value, searchSelection)
}

const keyButtonMap: Record<string, HTMLButtonElement> = {
p: matchCaseEl,
w: wholeWordEl,
r: useRegExpEl,
l: inSelectionEl,
}

const elementHandlerMap = new Map<HTMLElement, () => any>([
[nextEl, () => move(true)],
[prevEl, () => move()],
[prevEl, move],
[closeEl, () => close(true)],
[
replaceEl,
() => {
if (!textarea.readOnly) {
selectNext = true
replaceAPI.replace(replaceInput.value)
}
},
],
[
replaceAllEl,
() => {
textarea.readOnly || replaceAPI.replaceAll(replaceInput.value, searchSelection)
},
],
[replaceEl, replace],
[replaceAllEl, replaceAll],
[
toggle,
() => {
Expand All @@ -228,6 +230,14 @@ export const searchWidget = (): SearchWidget => {
],
])

const shortcut = ` (Alt+${isMac ? "Cmd+" : ""}`

matchCaseEl.title = `Preserve Case${shortcut}P)`
wholeWordEl.title = `Match Whole Word${shortcut}W)`
useRegExpEl.title = `RegExmp Search${shortcut}R)`
inSelectionEl.title = `Find in Selection${shortcut}L)`
replaceAllEl.title = `(${isMac ? "Cmd" : "Ctrl+Alt"}+Enter)`

textarea.addEventListener("keydown", keydown)

// Patches a selection bug when moving focus from the textarea to the buttons on the widget
Expand All @@ -242,9 +252,11 @@ export const searchWidget = (): SearchWidget => {
container.addEventListener("click", e => {
const target = <HTMLElement>e.target
elementHandlerMap.get(<HTMLElement>target)?.()
if (target.matches(".search-options button")) {
if (target.matches("input~*")) target.focus()
if (target.matches(".search-options>button")) {
toggleAttr(target, "aria-pressed")
startSearch(true)
e.isTrusted && target.focus()
}
})

Expand All @@ -255,24 +267,19 @@ export const searchWidget = (): SearchWidget => {
target = <HTMLElement>e.target,
key = e.key,
isFind = target == findInput
if (shortcut == 1) {
const input =
key == "c"
? matchCaseEl
: key == "w"
? wholeWordEl
: key == "r"
? useRegExpEl
: key == "l"
? inSelectionEl
: 0

if (input) preventDefault(e), input.click()
if (shortcut == (isMac ? 5 : 1)) {
let input = keyButtonMap[isMac ? e.code[3].toLowerCase() : key]
if (input) {
preventDefault(e)
input.click()
target.focus()
}
} else if (key == "Enter" && target.tagName == "INPUT") {
preventDefault(e)
if (!shortcut) (isFind ? nextEl : replaceEl).click()
else if (shortcut == 8 && isFind) prevEl.click()
else if (shortcut == 3 && !isFind) replaceAllEl.click()
if (!shortcut) isFind ? move(true) : replace()
else if (shortcut == 8 && isFind) move()
else if (shortcut == (isMac ? 4 : 3) && !isFind) replaceAll()
target.focus()
} else if (!shortcut && key == "Escape") close(true)
else keydown(e)
})
Expand Down
2 changes: 1 addition & 1 deletion package/src/themes/night-owl.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Original: https://github.com/sdras/night-owl-vscode-theme */
}

.search-matches .match {
--widget__bg-find: #545A8B;
--widget__bg-find: #545a8b;
}

.active-line {
Expand Down
3 changes: 2 additions & 1 deletion package/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export interface PrismEditor extends EventHandler<EditorEventMap> {
/** Gets `selectionStart`, `selectionEnd` and `selectionDirection` for the `textarea`. */
getSelection(): InputSelection
/**
* Sets the selection for the `textarea` and synchronously runs the selectionChange listeners.
* Sets the selection for the `textarea` and synchronously runs the selectionChange listeners.
* Focuses the textarea in Safari.
* @param start New selectionStart
* @param end New selectionEnd
* @param direction New direction
Expand Down

0 comments on commit b5d4f21

Please sign in to comment.