Skip to content

Commit

Permalink
Adds matching options to graph search
Browse files Browse the repository at this point in the history
  • Loading branch information
d13 authored and eamodio committed Sep 23, 2022
1 parent d5e7bea commit 2ee37c4
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 64 deletions.
29 changes: 10 additions & 19 deletions src/webviews/apps/plus/graph/GraphWrapper.tsx
Expand Up @@ -26,7 +26,7 @@ import type {
import type { Subscription } from '../../../../subscription';
import { getSubscriptionTimeRemaining, SubscriptionState } from '../../../../subscription';
import { pluralize } from '../../../../system/string';
import { SearchNav } from '../../shared/components/search/search-nav-react';
import { SearchField, SearchNav } from '../../shared/components/search/react';
import type { DateTimeFormat } from '../../shared/date';
import { formatDate, fromNow } from '../../shared/date';

Expand Down Expand Up @@ -314,16 +314,16 @@ export function GraphWrapper({
}
};

const handleSearchInput = (e: FormEvent<HTMLInputElement>) => {
const currentValue = e.currentTarget.value;
setSearchValue(currentValue);
const handleSearchInput = (e: CustomEvent<SearchPattern>) => {
const detail = e.detail;
setSearchValue(detail.pattern);

if (currentValue.length < 3) {
if (detail.pattern.length < 3) {
setSearchResultKey(undefined);
setSearchIds(undefined);
return;
}
onSearchCommits?.({ pattern: currentValue });
onSearchCommits?.(detail);
};

useLayoutEffect(() => {
Expand Down Expand Up @@ -584,19 +584,10 @@ export function GraphWrapper({
</section>
<header className="titlebar graph-app__header">
<div className="titlebar__group">
<div role="search" className="search-input">
<label htmlFor="titlebar-search">
<span className="codicon codicon-search" aria-label="Search" title="Search"></span>
</label>
<input
id="titlebar-search"
type="search"
spellCheck="false"
placeholder="Search..."
value={searchValue}
onChange={e => handleSearchInput(e)}
/>
</div>
<SearchField
value={searchValue}
onChange={e => handleSearchInput(e as CustomEvent<SearchPattern>)}
/>
<SearchNav
aria-label="Graph search navigation"
step={searchPosition}
Expand Down
35 changes: 0 additions & 35 deletions src/webviews/apps/plus/graph/graph.scss
Expand Up @@ -514,41 +514,6 @@ a {
}
}

.search-input {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 0.8rem;

label {
color: var(--vscode-input-foreground);
}
input {
width: 30rem;
height: 2.4rem;
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-background); // var(--vscode-input-foreground);
border-radius: 0.25rem;
padding: {
left: 0.4rem;
right: 0.4rem;
}

&:focus {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}

&::placeholder {
color: var(--vscode-input-placeholderForeground);
}
&:focus {
border-color: var(--vscode-focusBorder);
}
}
}

.titlebar {
background: var(--vscode-titleBar-inactiveBackground);
color: var(--vscode-titleBar-inactiveForeground);
Expand Down
19 changes: 19 additions & 0 deletions src/webviews/apps/shared/components/search/react.tsx
@@ -0,0 +1,19 @@
import { provideReactWrapper } from '@microsoft/fast-react-wrapper';
import React from 'react';
import { SearchField as fieldComponent } from './search-field';
import { SearchNav as navComponent } from './search-nav';

const { wrap } = provideReactWrapper(React);

export const SearchField = wrap(fieldComponent, {
events: {
onChange: 'change',
},
});

export const SearchNav = wrap(navComponent, {
events: {
onPrevious: 'previous',
onNext: 'next',
},
});
181 changes: 181 additions & 0 deletions src/webviews/apps/shared/components/search/search-field.ts
@@ -0,0 +1,181 @@
import { attr, css, customElement, FASTElement, html } from '@microsoft/fast-element';
import '../codicon';

// match case is disabled unless regex is true
const template = html<SearchField>`
<template role="search">
<label htmlFor="search">
<code-icon icon="search" aria-label="${x => x.label}" title="${x => x.label}"></code-icon>
</label>
<input
id="search"
type="search"
spellcheck="false"
placeholder="${x => x.placeholder}"
value="${x => x.value}"
@input="${(x, c) => x.handleInput(c.event)}"
/>
<div class="controls">
<button
type="button"
role="checkbox"
aria-label="Match All"
title="Match All"
aria-checked="${x => x.all}"
@click="${(x, c) => x.handleAll(c.event)}"
>
<code-icon icon="whole-word"></code-icon>
</button>
<button
type="button"
role="checkbox"
aria-label="Match Case in Regular Expression"
title="Match Case in Regular Expression"
?disabled="${x => !x.regex}"
aria-checked="${x => x.case}"
@click="${(x, c) => x.handleCase(c.event)}"
>
<code-icon icon="case-sensitive"></code-icon>
</button>
<button
type="button"
role="checkbox"
aria-label="Use Regular Expression"
title="Use Regular Expression"
aria-checked="${x => x.regex}"
@click="${(x, c) => x.handleRegex(c.event)}"
>
<code-icon icon="regex"></code-icon>
</button>
</div>
</template>
`;

const styles = css`
:host {
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 0.8rem;
position: relative;
}
label {
color: var(--vscode-input-foreground);
}
input {
width: 30rem;
height: 2.4rem;
background-color: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-background);
border-radius: 0.25rem;
padding: 0 6.6rem 0 0.4rem;
font-family: inherit;
font-size: 1rem;
}
input:focus {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
input::placeholder {
color: var(--vscode-input-placeholderForeground);
}
.controls {
position: absolute;
top: 0.2rem;
right: 0.2rem;
display: inline-flex;
flex-direction: row;
align-items: center;
gap: 0.1rem;
}
button {
display: inline-flex;
justify-content: center;
align-items: center;
width: 2rem;
height: 2rem;
padding: 0;
color: inherit;
border: none;
background: none;
text-align: center;
border-radius: 0.25rem;
}
button:focus:not([disabled]) {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
button:not([disabled]) {
cursor: pointer;
}
button:hover:not([disabled]) {
background-color: var(--vscode-inputOption-hoverBackground);
}
button[disabled] {
opacity: 0.5;
}
button[aria-checked='true'] {
background-color: var(--vscode-inputOption-activeBackground);
color: var(--vscode-inputOption-activeForeground);
}
`;

@customElement({
name: 'search-field',
template: template,
styles: styles,
})
export class SearchField extends FASTElement {
@attr
label = 'Search';

@attr
placeholder = 'Search...';

@attr
value = '';

@attr({ mode: 'boolean' })
all = false;

@attr({ mode: 'boolean' })
case = false;

@attr({ mode: 'boolean' })
regex = false;

handleInput(e: Event) {
const value = (e.target as HTMLInputElement)?.value;
this.value = value;
this.emitSearch();
}
handleAll(_e: Event) {
this.all = !this.all;
this.emitSearch();
}
handleCase(_e: Event) {
this.case = !this.case;
this.emitSearch();
}
handleRegex(_e: Event) {
this.regex = !this.regex;
if (!this.regex) {
this.case = false;
}
this.emitSearch();
}

emitSearch() {
this.$emit('change', {
pattern: this.value,
matchAll: this.all,
matchCase: this.case,
matchRegex: this.regex,
});
}
}
10 changes: 0 additions & 10 deletions src/webviews/apps/shared/components/search/search-nav-react.tsx

This file was deleted.

0 comments on commit 2ee37c4

Please sign in to comment.