Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add search web component #21177

Merged
merged 10 commits into from
Jan 6, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "feat: add search web component",
"packageName": "@fluentui/web-components",
"email": "jes@microsoft.com",
"dependentChangeType": "patch"
}
2 changes: 1 addition & 1 deletion packages/web-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"dependencies": {
"@microsoft/fast-colors": "^5.1.0",
"@microsoft/fast-element": "^1.6.0",
"@microsoft/fast-foundation": "^2.24.0",
"@microsoft/fast-foundation": "^2.27.1",
"@microsoft/fast-web-utilities": "^5.0.0",
"tslib": "^1.13.0"
}
Expand Down
2 changes: 2 additions & 0 deletions packages/web-components/src/component-definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ import fluentRadioDefinition from './radio/radio.vscode.definition.json';
export { fluentRadioDefinition };
import fluentRadioGroupDefinition from './radio-group/radio-group.vscode.definition.json';
export { fluentRadioGroupDefinition };
import fluentSearchDefinition from './search/search.vscode.definition.json';
export { fluentSearchDefinition };
import fluentSelectDefinition from './select/select.vscode.definition.json';
export { fluentSelectDefinition };
import fluentSkeletonDefinition from './skeleton/skeleton.vscode.definition.json';
Expand Down
3 changes: 3 additions & 0 deletions packages/web-components/src/custom-elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { fluentNumberField } from './number-field/index';
import { fluentProgress, fluentProgressRing } from './progress/index';
import { fluentRadio } from './radio/index';
import { fluentRadioGroup } from './radio-group/index';
import { fluentSearch } from './search/index';
import { fluentSelect } from './select/index';
import { fluentSkeleton } from './skeleton/index';
import { fluentSlider } from './slider/index';
Expand Down Expand Up @@ -70,6 +71,7 @@ export {
fluentProgressRing,
fluentRadio,
fluentRadioGroup,
fluentSearch,
fluentSelect,
fluentSkeleton,
fluentSlider,
Expand Down Expand Up @@ -120,6 +122,7 @@ export const allComponents = {
fluentProgressRing,
fluentRadio,
fluentRadioGroup,
fluentSearch,
fluentSelect,
fluentSkeleton,
fluentSlider,
Expand Down
1 change: 1 addition & 0 deletions packages/web-components/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export * from './number-field/';
export * from './progress/';
export * from './radio/';
export * from './radio-group/';
export * from './search/';
export * from './select';
export * from './skeleton/';
export * from './slider/';
Expand Down
10 changes: 3 additions & 7 deletions packages/web-components/src/listbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Listbox, listboxTemplate as template } from '@microsoft/fast-foundation';
import { Listbox as FoundationListboxElement, listboxTemplate as template } from '@microsoft/fast-foundation';
import { listboxStyles as styles } from './listbox.styles';

export class Listbox extends FoundationListboxElement {}

/**
* The Fluent listbox Custom Element. Implements, {@link @microsoft/fast-foundation#Listbox}
* {@link @microsoft/fast-foundation#listboxTemplate}
Expand All @@ -22,9 +24,3 @@ export const fluentListbox = Listbox.compose({
* @public
*/
export const listboxStyles = styles;

/**
* Listbox base class
* @public
*/
export { Listbox };
109 changes: 109 additions & 0 deletions packages/web-components/src/search/fixtures/search.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<h1>Search</h1>
<h4>Default</h4>
<fluent-search></fluent-search>
<fluent-search>Label</fluent-search>

<h4>Full Width</h4>
<fluent-search style="width: 100%"></fluent-search>

<h4>Placeholder</h4>
<fluent-search placeholder="Placeholder"></fluent-search>

<!-- Required -->
<h4>Required</h4>
<fluent-search required></fluent-search>

<!-- Disabled -->
<h4>Disabled</h4>
<fluent-search disabled></fluent-search>
<fluent-search disabled>label</fluent-search>
<fluent-search disabled placeholder="placeholder"></fluent-search>
<fluent-search disabled>
<svg slot="start" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
/>
</svg>
</fluent-search>

<!-- Read only -->
<h4>Read only</h4>
<fluent-search readonly value="Readonly"></fluent-search>
<fluent-search readonly value="Readonly">label</fluent-search>

<!-- Read only -->
<h4>Autofocus</h4>
<fluent-search autofocus>autofocus</fluent-search>

<!-- Start -->
<h4>With start</h4>
<fluent-search>
<svg slot="start" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
/>
</svg>
</fluent-search>

<!-- End -->
<h4>With end</h4>
<fluent-search>
<svg slot="end" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
/>
</svg>
</fluent-search>

<h4>Filled</h4>
<h5>Default</h5>
<fluent-search appearance="filled"></fluent-search>
<fluent-search appearance="filled">label</fluent-search>

<h5>Placeholder</h5>
<fluent-search appearance="filled" placeholder="Placeholder"></fluent-search>

<!-- Required -->
<h5>Required</h5>
<fluent-search appearance="filled" required></fluent-search>

<!-- Disabled -->
<h5>Disabled</h5>
<fluent-search appearance="filled" disabled></fluent-search>
<fluent-search appearance="filled" disabled>label</fluent-search>
<fluent-search appearance="filled" disabled placeholder="placeholder"></fluent-search>
<fluent-search appearance="filled" disabled>
<svg slot="start" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 5.5a1 1 0 100 2 1 1 0 000-2zm-5 1a1 1 0 112 0 1 1 0 01-2 0zm3.5-4a.5.5 0 00-1 0V3h-3C5.67 3 5 3.67 5 4.5v4c0 .83.67 1.5 1.5 1.5h7c.83 0 1.5-.67 1.5-1.5v-4c0-.83-.67-1.5-1.5-1.5h-3v-.5zM6.5 4h7c.28 0 .5.22.5.5v4a.5.5 0 01-.5.5h-7a.5.5 0 01-.5-.5v-4c0-.28.22-.5.5-.5zm3.75 14c2.62-.04 4.2-.6 5.12-1.44A3.52 3.52 0 0016.5 14h.01v-.69c0-1-.81-1.8-1.8-1.8h-3.2v-.01H5.3c-.99 0-1.8.81-1.8 1.81v.7c.04.77.25 1.75 1.13 2.55.93.84 2.5 1.4 5.12 1.44h.5zm-4.94-5.5h9.38c.45 0 .81.37.81.81v.44c0 .69-.13 1.46-.8 2.07C14 16.45 12.66 17 10 17s-4.01-.55-4.7-1.18a2.63 2.63 0 01-.8-2.07v-.44c0-.44.36-.8.8-.8z"
/>
</svg>
</fluent-search>

<!-- Read only -->
<h5>Read only</h5>
<fluent-search appearance="filled" readonly value="Readonly"></fluent-search>
<fluent-search appearance="filled" readonly value="Readonly">label</fluent-search>

<!-- With label -->
<h4>Visual vs audio label</h4>
<fluent-search>
<span aria-label="Audio label">Visible label</span>
</fluent-search>

<!-- With hidden label -->
<h4>Audio label only</h4>
<fluent-search>
<span aria-label="Audio label only"></span>
</fluent-search>

<!-- With aria-label -->
<h4>With aria-label</h4>
<fluent-search aria-label="Search with aria-label"></fluent-search>

<form class="form" name="myForm" action="#">
<!-- In a form -->
<h2>In a form</h2>
<fluent-search name="fname" aria-label="Search with aria-label"></fluent-search>
<input type="submit" value="submit" />
</form>
56 changes: 56 additions & 0 deletions packages/web-components/src/search/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { attr } from '@microsoft/fast-element';
import { Search as FoundationSearch, SearchOptions } from '@microsoft/fast-foundation';
import { searchTemplate as template } from './search.template';
import { searchStyles as styles } from './search.styles';

/**
* Search appearances
* @public
*/
export type SearchAppearance = 'filled' | 'outline';

/**
* The Fluent search class
* @internal
*/
export class Search extends FoundationSearch {
/**
* The appearance of the element.
*
* @public
* @remarks
* HTML Attribute: appearance
*/
@attr
public appearance: SearchAppearance = 'outline';
}

/**
* The Fluent Search Custom Element. Implements {@link @microsoft/fast-foundation#Search},
* {@link @microsoft/fast-foundation#searchTemplate}
*
*
* @public
* @remarks
* HTML Element: \<fluent-search\>
*
* {@link https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/delegatesFocus | delegatesFocus}
*/
export const fluentSearch = Search.compose<SearchOptions>({
baseName: 'search',
baseClass: FoundationSearch,
template,
styles,
start: `<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg%22%3E"><path d="M8.5 3a5.5 5.5 0 0 1 4.23 9.02l4.12 4.13a.5.5 0 0 1-.63.76l-.07-.06-4.13-4.12A5.5 5.5 0 1 1 8.5 3Zm0 1a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9Z"/></svg>`,
shadowOptions: {
delegatesFocus: true,
},
});

export * from './search.template';

/**
* Styles for Search
* @public
*/
export const searchStyles = styles;
104 changes: 104 additions & 0 deletions packages/web-components/src/search/search.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { fluentSearch } from './index';

export default {
title: 'Components/Search',
component: fluentSearch,
argTypes: {
appearance: {
options: ['filled', 'outline'],
defaultValue: 'outline',
control: { type: 'radio' },
},
autoFocus: {
description: 'Automatically focuses the control',
control: { type: 'boolean' },
},
disabled: {
description: 'The search box should be submitted with the form but should not be editable',
control: { type: 'boolean' },
},
list: {
control: { type: 'text' },
},
maxlength: {
control: { type: 'number' },
},
name: {
control: { type: 'text' },
},
minlength: {
control: { type: 'number' },
},
pattern: {
description: `A regular expression the input's contents must match in order to be valid`,
control: { type: 'text' },
},
placeholder: {
description: 'An exemplar value to display in the input field whenever it is empty',
defaultValue: 'Placeholder',
control: { type: 'text' },
},
readonly: {
control: { type: 'boolean' },
},
required: {
control: { type: 'boolean' },
},
spellcheck: {
control: { type: 'boolean' },
},
},
};

const SearchTemplate = ({
appearance,
autoFocus,
disabled,
list,
maxlength,
name,
minlength,
pattern,
placeholder,
readonly,
required,
size,
spellcheck,
}) =>
`<fluent-search
${appearance ? `appearance="${appearance}"` : ''}
${autoFocus ? 'autofocus' : ''}
${disabled ? 'disabled' : ''}
${list ? `list="${list}"` : ''}
${maxlength ? `maxlength="${maxlength}"` : ''}
${name ? `name="${name}"` : ''}
${minlength ? `minlength="${minlength}"` : ''}
${pattern ? `pattern="${pattern}"` : ''}
${placeholder ? `placeholder="${placeholder}"` : ''}
${readonly ? 'readonly' : ''}
${required ? 'required' : ''}
${spellcheck ? `spellcheck="${spellcheck}"` : ''}
${size ? `size="${size}"` : ''}
></fluent-search>`;

export const Search = SearchTemplate.bind({});

Search.args = {
placeholder: 'placeholder',
autoFocus: false,
disabled: false,
readonly: false,
required: false,
};

const example = `
<fluent-search appearance="outline"></fluent-search>
`;

Search.parameters = {
docs: {
source: {
code: example,
},
},
};
Loading