576bcf554f
I originally planned to add component documentation, but as this dragged on and I found that JSDoc-to-Markdown sometimes needed hand-tuning, I decided to skip it and focus on replicating what was already present in Freestyle. Adding documentation is a finite task that can be revisited in the future.
My goal was to migrate everything from Freestyle with as few changes as possible. Some adaptations that I found necessary:
• the DelayedArray and DelayedTruth utilities that delay component rendering until slightly after initial render because without them:
◦ charts were rendering with zero width
◦ the JSON viewer was rendering with empty content
• Storybook in Ember renders components in a routerless/controllerless context by default, so some component stories needed changes:
◦ table pagination/sorting stories access to query params, which necessitates some reaching into Ember internals to start routing and dynamically generate a Storybook route/controller to render components into
◦ some stories have a faux controller as part of their Storybook context that hosts setInterval-linked dynamic computed properties
• some jiggery-pokery with anchor tags
◦ inert href='#' had to become href='javascript:;
◦ links that are actually meant to navigate need target='_parent' so they don’t navigate inside the Storybook iframe
Maybe some of these could be addressed by fixes in ember-cli-storybook but I’m wary of digging around in there any more than I already have, as I’ve lost a lot of time to Storybook confusion and frustrations already 😞
The STORYBOOK=true environment variable tweaks some environment settings to get things working as expected in the Storybook context.
I chose to:
• use angle bracket invocation within stories rather than have to migrate them soon after having moved to Storybook
• keep Freestyle around for now for its palette and typeface components
132 lines
4.1 KiB
JavaScript
132 lines
4.1 KiB
JavaScript
import hbs from 'htmlbars-inline-precompile';
|
|
|
|
export default {
|
|
title: 'Components|Multi-Select Dropdown',
|
|
};
|
|
|
|
let options1 = [
|
|
{ key: 'option-1', label: 'Option One' },
|
|
{ key: 'option-2', label: 'Option Two' },
|
|
{ key: 'option-3', label: 'Option Three' },
|
|
{ key: 'option-4', label: 'Option Four' },
|
|
{ key: 'option-5', label: 'Option Five' },
|
|
];
|
|
|
|
let selection1 = ['option-2', 'option-4', 'option-5'];
|
|
|
|
export let Standard = () => {
|
|
return {
|
|
template: hbs`
|
|
<h5 class="title is-5">Multi-Select Dropdown</h5>
|
|
<MultiSelectDropdown
|
|
@label="Example Dropdown"
|
|
@options={{options1}}
|
|
@selection={{selection1}}
|
|
@onSelect={{action (mut selection1)}} />
|
|
<p class="annotation">A wrapper around basic-dropdown for creating a list of checkboxes and tracking the state thereof.</p>
|
|
`,
|
|
context: {
|
|
options1,
|
|
selection1,
|
|
},
|
|
};
|
|
};
|
|
|
|
export let RightAligned = () => {
|
|
return {
|
|
template: hbs`
|
|
<h5 class="title is-5">Multi-Select Dropdown right-aligned</h5>
|
|
<div style="display:flex; justify-content:flex-end">
|
|
<MultiSelectDropdown
|
|
@label="Example right-aligned Dropdown"
|
|
@options={{options1}}
|
|
@selection={{selection1}}
|
|
@onSelect={{action (mut selection1)}} />
|
|
</div>
|
|
`,
|
|
context: {
|
|
options1,
|
|
selection1,
|
|
},
|
|
};
|
|
};
|
|
|
|
export let ManyOptions = () => {
|
|
return {
|
|
template: hbs`
|
|
<h5 class="title is-5">Multi-Select Dropdown with many options</h5>
|
|
<MultiSelectDropdown
|
|
@label="Lots of options in here"
|
|
@options={{optionsMany}}
|
|
@selection={{selectionMany}}
|
|
@onSelect={{action (mut selectionMany)}} />
|
|
<p class="annotation">
|
|
A strength of the multi-select-dropdown is its simple presentation. It is quick to select options and it is quick to remove options.
|
|
However, this strength becomes a weakness when there are too many options. Since the selection isn't pinned in any way, removing a selection
|
|
can become an adventure of scrolling up and down. Also since the selection isn't pinned, this component can't support search, since search would
|
|
entirely mask the selection.
|
|
</p>
|
|
`,
|
|
context: {
|
|
optionsMany: Array(100)
|
|
.fill(null)
|
|
.map((_, i) => ({ label: `Option ${i}`, key: `option-${i}` })),
|
|
selectionMany: [],
|
|
},
|
|
};
|
|
};
|
|
|
|
export let Bar = () => {
|
|
return {
|
|
template: hbs`
|
|
<h5 class="title is-5">Multi-Select Dropdown bar</h5>
|
|
<div class="button-bar">
|
|
<MultiSelectDropdown
|
|
@label="Datacenter"
|
|
@options={{optionsDatacenter}}
|
|
@selection={{selectionDatacenter}}
|
|
@onSelect={{action (mut selectionDatacenter)}} />
|
|
<MultiSelectDropdown
|
|
@label="Type"
|
|
@options={{optionsType}}
|
|
@selection={{selectionType}}
|
|
@onSelect={{action (mut selectionType)}} />
|
|
<MultiSelectDropdown
|
|
@label="Status"
|
|
@options={{optionsStatus}}
|
|
@selection={{selectionStatus}}
|
|
@onSelect={{action (mut selectionStatus)}} />
|
|
</div>
|
|
<p class="annotation">
|
|
Since this is a core component for faceted search, it makes sense to letruct an arrangement of multi-select dropdowns.
|
|
Do this by wrapping all the options in a <code>.button-bar</code> container.
|
|
</p>
|
|
`,
|
|
context: {
|
|
optionsDatacenter: [
|
|
{ key: 'pdx-1', label: 'pdx-1' },
|
|
{ key: 'jfk-1', label: 'jfk-1' },
|
|
{ key: 'jfk-2', label: 'jfk-2' },
|
|
{ key: 'muc-1', label: 'muc-1' },
|
|
],
|
|
selectionDatacenter: ['jfk-1', 'jfk-2'],
|
|
|
|
optionsType: [
|
|
{ key: 'batch', label: 'Batch' },
|
|
{ key: 'service', label: 'Service' },
|
|
{ key: 'system', label: 'System' },
|
|
{ key: 'periodic', label: 'Periodic' },
|
|
{ key: 'parameterized', label: 'Parameterized' },
|
|
],
|
|
selectionType: ['system', 'service'],
|
|
|
|
optionsStatus: [
|
|
{ key: 'pending', label: 'Pending' },
|
|
{ key: 'running', label: 'Running' },
|
|
{ key: 'dead', label: 'Dead' },
|
|
],
|
|
selectionStatus: [],
|
|
},
|
|
};
|
|
};
|