Skip to content

Instantly share code, notes, and snippets.

@obie
Created November 5, 2020 01:24
Show Gist options
  • Save obie/342db3c594db62f6aecc8b7b1f2b0dca to your computer and use it in GitHub Desktop.
Save obie/342db3c594db62f6aecc8b7b1f2b0dca to your computer and use it in GitHub Desktop.
Search Implementation using stimulus, shoelace, and mark.js
.spreadsheet--search.grid.grid-flow-col.grid-cols-auto.gap-0.auto-cols-fr.pl-1.pr-8.hidden{ data: { controller: "spreadsheet--search", action: "toggle-search@window->spreadsheet--search#toggleSearch" }}
.input.col-span-9.p-2
%sl-input.w-full(placeholder="Search" size="small" clearable pill){ data: { target: "spreadsheet--search.input"}}
%sl-icon(name="search" slot="prefix")
%sl-dropdown(slot="suffix" placement="bottom-end" hoist){ data: { target: "spreadsheet--search.dropdown"}}
%sl-button(slot="trigger" caret type="text" size="small"){ data: { target: "spreadsheet--search.trigger"}} Highlight
%sl-menu
%sl-menu-item{ data: { target: "spreadsheet--search.higlight"}, checked: true} Highlight
%sl-menu-item{ data: { target: "spreadsheet--search.filter"}} Filter
.search-results.text-center.p-3{ data: { target: "spreadsheet--search.results"}}
0 found
.search-actions.text-right.p-2.flex
%sl-icon-button(name="caret-up-fill" label="Previous"){ data: { target: "spreadsheet--search.previous" }, class: "w-1/3"}
%sl-icon-button(name="caret-down-fill" label="Next"){ data: { target: "spreadsheet--search.next"}, class: "w-1/3"}
%sl-icon-button(name="x-circle-fill" label="Close"){ data: { target: "spreadsheet--search.cancel"}, class: "w-1/3"}
import { Controller } from 'stimulus'
import Mark from 'mark.js';
import hotkeys from 'hotkeys-js';
export default class extends Controller {
static targets = ['input','dropdown', 'trigger', 'filter','highlight','results','next','previous','cancel']
connect() {
this.inputTarget.addEventListener("sl-input", this.input.bind(this))
this.inputTarget.addEventListener("sl-clear", this.input.bind(this))
this.dropdownTarget.addEventListener("sl-select", this.selectMode.bind(this))
this.cancelTarget.addEventListener("click", this.cancel.bind(this))
this.previousTarget.addEventListener("click", this.previous.bind(this))
this.nextTarget.addEventListener("click", this.next.bind(this))
this.marker = new Mark(".spreadsheet--sheet .searchable")
hotkeys("ctrl+f, command+f", (event, handler) => {
event.preventDefault();
this.toggleSearch();
})
}
input(event) {
const value = event.target.value;
this.mark(value)
if(this.filterTarget.checked) {
this.element.closest(".spreadsheet--sheet").querySelectorAll(".spreadsheet--row").forEach((row) => {
if(row.querySelector("mark") || value == "") {
row.classList.remove("hidden")
}
else {
row.classList.add("hidden")
}
})
// remove the rows that don't match
}
}
mark(value) {
this.marker.unmark()
this.marker.mark(value,
{
done: (num) => {
this.currentMarkIndex = -1
this.resultsTarget.innerHTML = `${num} found`
}
}
)
}
currentMarks() {
return this.element.closest(".spreadsheet--sheet").querySelectorAll("mark")
}
selectMode(event) {
console.log('selectMode');
const selectedItem = event.detail.item;
this.triggerTarget.textContent = selectedItem.textContent;
[...this.dropdownTarget.querySelectorAll('sl-menu-item')].map(item => item.checked = item === selectedItem);
}
previous() {
const marks = this.currentMarks();
if(this.currentMarkIndex > 0) {
this.currentMarkIndex -= 1
marks.forEach((m) => m.classList.remove("current"))
marks[this.currentMarkIndex].classList.add("current")
this.resultsTarget.innerHTML = `${this.currentMarkIndex + 1} of ${marks.length} found`
}
}
next() {
const marks = this.currentMarks();
if(this.currentMarkIndex < (marks.length - 1)) {
this.currentMarkIndex += 1
marks.forEach((m) => m.classList.remove("current"))
marks[this.currentMarkIndex].classList.add("current")
this.resultsTarget.innerHTML = `${this.currentMarkIndex + 1} of ${marks.length} found`
}
}
cancel() {
console.log('cancel');
this.marker.unmark()
this.toggleSearch();
}
toggleSearch() {
this.element.classList.toggle("hidden")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment