Skip to content

Commit

Permalink
Add support for multi-line queries to LocalNavSearch component of UI …
Browse files Browse the repository at this point in the history
…Framework.
  • Loading branch information
cjcenizal committed May 23, 2017
1 parent 66c6db0 commit 9237e9e
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
35 changes: 35 additions & 0 deletions ui_framework/components/local_nav/_local_search.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/**
* 1. If we're using an expandable input, make sure that it doesn't force sibling elements to expand
* with it.
*/
.kuiLocalSearch {
display: flex;
align-items: flex-start; /* 1 */
width: 100%;
}

Expand Down Expand Up @@ -52,6 +57,36 @@
border-radius: 0;
}

/**
* 1. When it expands, the search input should lie on top of the content.
* 2. Expand as the user enters text.
* 3. Cap the height so that we can offer auto-completion suggestions below the input.
* 4. When the input is collapsed, we want text input to be truncated with an ellipsis.
*/
.kuiLocalSearchInput--expandable {
height: $localSearchHeight;
line-height: $globalLineHeight;
word-break: break-all; /* 4 */
white-space: nowrap; /* 4 */
overflow: hidden; /* 4 */
text-overflow: ellipsis; /* 4 */

&:focus {
z-index: 1; /* 1 */
height: auto; /* 2 */
max-height: 180px; /* 3 */
white-space: normal;
overflow: auto; /* 3 */
box-shadow: 0 5px 22px rgba(#000000, 0.25); /* 1 */
}

p {
margin: 0;
font-size: inherit;
line-height: inherit;
}
}

/**
* 1. Override inherited styles.
*/
Expand Down
43 changes: 43 additions & 0 deletions ui_framework/dist/ui_framework.css
Original file line number Diff line number Diff line change
Expand Up @@ -1771,11 +1771,20 @@ body {
align-items: flex-start;
/* 1 */ }

/**
* 1. If we're using an expandable input, make sure that it doesn't force sibling elements to expand
* with it.
*/
.kuiLocalSearch {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: start;
-webkit-align-items: flex-start;
-ms-flex-align: start;
align-items: flex-start;
/* 1 */
width: 100%; }

.kuiLocalSearchInput {
Expand Down Expand Up @@ -1914,6 +1923,40 @@ body {
background-image: url('data:image/svg+xml;utf8,<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z" fill="#CECECE"/></svg>');
/* 1 */ }

/**
* 1. When it expands, the search input should lie on top of the content.
* 2. Expand as the user enters text.
* 3. Cap the height so that we can offer auto-completion suggestions below the input.
* 4. When the input is collapsed, we want text input to be truncated with an ellipsis.
*/
.kuiLocalSearchInput--expandable {
height: 30px;
line-height: 1.5;
word-break: break-all;
/* 4 */
white-space: nowrap;
/* 4 */
overflow: hidden;
/* 4 */
text-overflow: ellipsis;
/* 4 */ }
.kuiLocalSearchInput--expandable:focus {
z-index: 1;
/* 1 */
height: auto;
/* 2 */
max-height: 180px;
/* 3 */
white-space: normal;
overflow: auto;
/* 3 */
box-shadow: 0 5px 22px rgba(0, 0, 0, 0.25);
/* 1 */ }
.kuiLocalSearchInput--expandable p {
margin: 0;
font-size: inherit;
line-height: inherit; }

/**
* 1. Override inherited styles.
*/
Expand Down
26 changes: 26 additions & 0 deletions ui_framework/doc_site/src/views/local_nav/local_nav_example.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { renderToHtml } from '../../services';

import {
GuideCode,
GuideDemo,
GuidePage,
GuideSection,
Expand Down Expand Up @@ -42,6 +43,8 @@ import { LocalNavWithTabs } from './local_nav_tabs';
import localNavWithTabsSource from '!!raw!./local_nav_tabs';
const localNavWithTabsHtml = renderToHtml(LocalNavWithTabs);

const searchMultiLineHtml = require('./local_nav_search_multi_line.html');
const searchMultiLineJs = require('raw!./local_nav_search_multi_line.js');
const datePickerHtml = require('./local_nav_date_picker.html');

export default props => (
Expand Down Expand Up @@ -124,6 +127,29 @@ export default props => (
</GuideDemo>
</GuideSection>

<GuideSection
title="Multi-line search"
source={[{
type: GuideSectionTypes.HTML,
code: searchMultiLineHtml,
}]}
>
<GuideText>
By using <GuideCode>contenteditable</GuideCode>, you can support multi-line queries. You&rsquo;ll
have to supply your own logic for switching between single-line and multi-line input values.
</GuideText>

<GuideDemo
html={searchMultiLineHtml}
js={searchMultiLineJs}
/>

<GuideDemo
html={searchMultiLineHtml}
isDarkTheme={true}
/>
</GuideSection>

<GuideSection
title="Invalid Search"
source={[
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<div class="kuiLocalNav">
<div class="kuiLocalNavRow">
<div class="kuiLocalNavRow__section">
<div class="kuiLocalBreadcrumbs">
<div class="kuiLocalBreadcrumb">
<a class="kuiLocalBreadcrumb__link" href="#">
Discover
</a>
</div>

<div class="kuiLocalBreadcrumb">
<a class="kuiLocalBreadcrumb__link" href="#">
<span class="kuiLocalBreadcrumb__emphasis">0</span> hits
</a>
</div>
</div>
</div>

<div class="kuiLocalNavRow__section">
<div class="kuiLocalMenu">
<button class="kuiLocalMenuItem">
New
</button>

<button class="kuiLocalMenuItem">
Save
</button>

<button class="kuiLocalMenuItem">
Open
</button>

<button class="kuiLocalMenuItem">
<div class="kuiLocalMenuItem__icon kuiIcon fa-clock-o"></div>
Last 5 minutes
</button>
</div>
</div>
</div>

<div class="kuiLocalNavRow kuiLocalNavRow--secondary">
<div class="kuiLocalSearch">
<div
id="expandableSearchInput"
class="kuiLocalSearchInput kuiLocalSearchInput--expandable"
contenteditable
>
</div>

<input
class="kuiLocalSearchInput kuiLocalSearchInput--secondary"
type="text"
placeholder="Another input"
autocomplete="off"
style="width: 150px"
>

<select class="kuiLocalSearchSelect">
<option>Alligator</option>
<option>Balaclava</option>
<option>Castanets</option>
</select>

<button class="kuiLocalSearchButton">
<span class="kuiIcon fa-search"></span>
</button>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable */

const $searchInput = $('#expandableSearchInput');
let multiLineInputValue = '(.es(\'"this&nbsp;&nbsp;&nbsp;&nbsp;"&nbsp;AND&nbsp;&nbsp;" that"&nbsp;&nbsp;\',&nbsp;metric=sum:bytes),&nbsp;.es(\'foo OR bar\')).divide(.es(-foo)).multiply(100).holt(0.1,0.1,0.1,1w),<br><br>.es(*).label(\'This is everything\')';

function formatMultiLineExpression(html) {
// Preserve whitespace because people can use it to organize parts of a query to make it easier
// to understand.
const encodedWhitespace = html.replace(/ /g, '&nbsp;');

// Replace divs with linebreaks.
const removeClosingDivs = html.replace(/<\/div>/g, '');
const breakOnOpeningDivs = removeClosingDivs.replace(/<div>/g, '<br>');

// Preserve line-breaks.
const splitOnBreaks = breakOnOpeningDivs.split(/\r?\n/g);
return splitOnBreaks.join('<br>');
}

function formatSingleLineExpression(html) {
// Allow whitespace to collapse.
const encodedWhitespace = html.replace(/&nbsp;/g, ' ');

// Replace divs with linebreaks.
const removeClosingDivs = encodedWhitespace.replace(/<\/div>/g, '');
const breakOnOpeningDivs = removeClosingDivs.replace(/<div>/g, '\n');

// Preserve line-breaks.
const splitOnBreaks = breakOnOpeningDivs.split(/<br>/g);
return splitOnBreaks.join('\n');
}

// We have to sanitize pasted data into a contenteditable.
$searchInput.on('paste', e => {
e.preventDefault();

// If we're using jQuery, we need to dig in and get the original event. IE puts clipboardData
// on the window.
const data = (e.originalEvent || e).clipboardData || window.clipboardData;

// Strip out all HTML by just getting the text.
const text = data.getData('text');

const html = formatMultiLineExpression(text);

document.execCommand('insertHTML', false, html);
});

$searchInput.on('blur', () => {
// If the search input has been scrolled, we should make sure only the first line is visible
// if it loses focus and collapses.
$searchInput.scrollTop(0);

// Store input value.
multiLineInputValue = formatMultiLineExpression($searchInput.html());

// Display "preview mode" of input value.
const previewInput = formatSingleLineExpression($searchInput.html());
$searchInput.text(previewInput);
});

$searchInput.on('focus', () => {
// Display true input value.
$searchInput.html(multiLineInputValue);
});

// Init.
$searchInput.html(formatSingleLineExpression(multiLineInputValue));

0 comments on commit 9237e9e

Please sign in to comment.