This repository has been archived by the owner on Jun 29, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(fab): Floating Action Button (FAB) aka FABULOUS!!! component. (#824
) * FAB WIP * fab * cleanup * cleanup * cleanup * cleanup * usage, story, tests, readme, fix bg color * Fab styling and demos. * review fixes * remove dependency * feat: props and style for fab * Added appearance, scale, and icon props. * Minor style rule. e2e updates. Readme updates. * Added knobs for new FAB props. * import CSS object for .button * I FORGOT THE DOT! * Cleanup. * fix test maybe Co-authored-by: Alan Sangma <asangma@esri.com>
- Loading branch information
Showing
22 changed files
with
451 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { newE2EPage } from "@stencil/core/testing"; | ||
import { accessible, hidden, renders } from "../../tests/commonTests"; | ||
import { CSS } from "./resources"; | ||
|
||
describe("calcite-fab", () => { | ||
it("renders", async () => renders("calcite-fab")); | ||
|
||
it("honors hidden attribute", async () => hidden("calcite-fab")); | ||
|
||
it("should have visible text when text is enabled", async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent(`<calcite-fab text="hello world" text-enabled></calcite-fab>`); | ||
|
||
const button = await page.find(`calcite-fab >>> .${CSS.button}`); | ||
const text = button.textContent; | ||
|
||
expect(text).toBe("hello world"); | ||
}); | ||
|
||
it("should not have visible text when text is not enabled", async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent(`<calcite-fab text="hello world"></calcite-fab>`); | ||
|
||
const button = await page.find(`calcite-fab >>> .${CSS.button}`); | ||
const text = button.textContent; | ||
|
||
expect(text).toBe(""); | ||
}); | ||
|
||
it("should have label", async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent(`<calcite-fab text="hello world" label="hi"></calcite-fab>`); | ||
|
||
const button = await page.find(`calcite-fab >>> .${CSS.button}`); | ||
expect(button.getAttribute("title")).toBe("hi"); | ||
expect(button.getAttribute("aria-label")).toBe("hi"); | ||
}); | ||
|
||
it("should be disabled", async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent(`<calcite-fab disabled></calcite-fab>`); | ||
|
||
const button = await page.find(`calcite-fab >>> .${CSS.button}`); | ||
expect(button).toHaveAttribute("disabled"); | ||
}); | ||
|
||
it("should have appearance=outline", async () => { | ||
const page = await newE2EPage(); | ||
await page.setContent(`<calcite-fab text="hello world"></calcite-fab>`); | ||
|
||
const fab = await page.find(`calcite-fab >>> .${CSS.button}`); | ||
expect(fab.getAttribute("appearance")).toBe("outline"); | ||
}); | ||
|
||
it("should be accessible", async () => { | ||
await accessible(`<calcite-fab text="hello world"></calcite-fab>`); | ||
await accessible(`<calcite-fab text="hello world" disabled text-enabled></calcite-fab>`); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
:host { | ||
@extend %component-host; | ||
background-color: var(--calcite-app-background-transparent); | ||
} | ||
|
||
@import "../../scss/includes/_component"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { boolean, select, text, withKnobs } from "@storybook/addon-knobs"; | ||
import { | ||
Attributes, | ||
createComponentHTML as create, | ||
darkBackground, | ||
parseReadme, | ||
titlelessDocsPage | ||
} from "../../../.storybook/utils"; | ||
import readme from "./readme.md"; | ||
import { ATTRIBUTES } from "../../../.storybook/resources"; | ||
import { ICONS } from "./resources"; | ||
const { appearance, dir, scale, theme } = ATTRIBUTES; | ||
|
||
export default { | ||
title: "components|calcite-fab", | ||
decorators: [withKnobs], | ||
parameters: { | ||
backgrounds: darkBackground, | ||
docs: { | ||
page: titlelessDocsPage | ||
}, | ||
notes: parseReadme(readme) | ||
} | ||
}; | ||
|
||
const createAttributes: () => Attributes = () => [ | ||
{ | ||
name: "appearance", | ||
value: select("appearance", appearance.values, appearance.values[2]) | ||
}, | ||
{ | ||
name: "dir", | ||
value: select("dir", dir.values, dir.defaultValue) | ||
}, | ||
{ | ||
name: "disabled", | ||
value: boolean("disabled", false) | ||
}, | ||
{ | ||
name: "icon", | ||
value: text("icon", ICONS.plus) | ||
}, | ||
{ | ||
name: "label", | ||
value: text("label", "Label") | ||
}, | ||
{ | ||
name: "loading", | ||
value: boolean("loading", false) | ||
}, | ||
{ | ||
name: "text", | ||
value: text("text", "Text") | ||
}, | ||
{ | ||
name: "text-enabled", | ||
value: boolean("textEnabled", false) | ||
}, | ||
{ | ||
name: "scale", | ||
value: select("scale", scale.values, scale.defaultValue) | ||
}, | ||
{ | ||
name: "theme", | ||
value: select("theme", theme.values, theme.defaultValue) | ||
} | ||
]; | ||
|
||
export const basic = () => create("calcite-fab", createAttributes(), `<calcite-fab></calcite-fab>`); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { Component, Element, Host, Method, Prop, h } from "@stencil/core"; | ||
import { CalciteAppearance, CalciteScale, CalciteTheme } from "../interfaces"; | ||
import { CSS, ICONS } from "./resources"; | ||
import { focusElement, getElementDir } from "../utils/dom"; | ||
|
||
@Component({ | ||
tag: "calcite-fab", | ||
styleUrl: "calcite-fab.scss", | ||
shadow: true | ||
}) | ||
export class CalciteFab { | ||
// -------------------------------------------------------------------------- | ||
// | ||
// Properties | ||
// | ||
// -------------------------------------------------------------------------- | ||
|
||
/** | ||
* Used to set the button's appearance. Default is outline. | ||
*/ | ||
@Prop({ reflect: true }) appearance: CalciteAppearance = "outline"; | ||
|
||
/** | ||
* When true, disabled prevents interaction. This state shows items with lower opacity/grayed. | ||
*/ | ||
@Prop({ reflect: true }) disabled = false; | ||
|
||
/** | ||
* The name of the icon to display. The value of this property must match the icon name from https://esri.github.io/calcite-ui-icons/. | ||
*/ | ||
@Prop() icon?: string = ICONS.plus; | ||
|
||
/** | ||
* Label of the FAB, exposed on hover. If no label is provided, the label inherits what's provided for the `text` prop. | ||
*/ | ||
@Prop() label?: string; | ||
|
||
/** | ||
* When true, content is waiting to be loaded. This state shows a busy indicator. | ||
*/ | ||
@Prop({ reflect: true }) loading = false; | ||
|
||
/** | ||
* Specifies the size of the fab. | ||
*/ | ||
@Prop({ reflect: true }) scale: CalciteScale = "m"; | ||
|
||
/** | ||
* Text that accompanies the FAB icon. | ||
*/ | ||
@Prop() text?: string; | ||
|
||
/** | ||
* Indicates whether the text is displayed. | ||
*/ | ||
@Prop({ reflect: true }) textEnabled = false; | ||
|
||
/** | ||
* Used to set the component's color scheme. | ||
*/ | ||
@Prop({ reflect: true }) theme: CalciteTheme; | ||
|
||
// -------------------------------------------------------------------------- | ||
// | ||
// Private Properties | ||
// | ||
// -------------------------------------------------------------------------- | ||
|
||
@Element() el: HTMLCalciteFabElement; | ||
|
||
private buttonEl: HTMLElement; | ||
|
||
// -------------------------------------------------------------------------- | ||
// | ||
// Methods | ||
// | ||
// -------------------------------------------------------------------------- | ||
|
||
@Method() | ||
async setFocus() { | ||
focusElement(this.buttonEl); | ||
} | ||
|
||
// -------------------------------------------------------------------------- | ||
// | ||
// Render Methods | ||
// | ||
// -------------------------------------------------------------------------- | ||
|
||
render() { | ||
const { | ||
appearance, | ||
disabled, | ||
el, | ||
loading, | ||
scale, | ||
theme, | ||
textEnabled, | ||
icon, | ||
label, | ||
text | ||
} = this; | ||
const titleText = !textEnabled && text; | ||
const title = label || titleText; | ||
const dir = getElementDir(el); | ||
|
||
return ( | ||
<Host> | ||
<calcite-button | ||
class={CSS.button} | ||
loading={loading} | ||
disabled={disabled} | ||
title={title} | ||
aria-label={label} | ||
theme={theme} | ||
dir={dir} | ||
scale={scale} | ||
icon={icon} | ||
round={true} | ||
floating={true} | ||
width="auto" | ||
appearance={appearance} | ||
color="blue" | ||
ref={(buttonEl) => (this.buttonEl = buttonEl)} | ||
> | ||
{this.textEnabled ? this.text : null} | ||
</calcite-button> | ||
</Host> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# calcite-fab | ||
|
||
<!-- Auto Generated Below --> | ||
|
||
## Usage | ||
|
||
### Basic | ||
|
||
#### Without text | ||
|
||
Renders a `calcite-fab` that displays only an icon and a tooltip label. | ||
|
||
```html | ||
<calcite-fab label="Performs my custom action"></calcite-fab> | ||
``` | ||
|
||
#### With text | ||
|
||
Renders a `calcite-fab` that displays text along side an icon and a tooltip label. | ||
|
||
```html | ||
<calcite-fab label="Performs my custom action" text="Perform Action!" text-enabled></calcite-fab> | ||
``` | ||
|
||
#### Loading and disabled | ||
|
||
Renders a `calcite-fab` that is loading and disabled. | ||
|
||
```html | ||
<calcite-fab loading disabled></calcite-fab> | ||
``` | ||
|
||
## Properties | ||
|
||
| Property | Attribute | Description | Type | Default | | ||
| ------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ----------- | | ||
| `appearance` | `appearance` | Used to set the button's appearance. Default is outline. | `CalciteAppearance` | `outline` | | ||
| `disabled` | `disabled` | When true, disabled prevents interaction. This state shows items with lower opacity/grayed. | `boolean` | `false` | | ||
| `icon` | `icon` | The name of the icon to display. The value of this property must match the icon name from https://esri.github.io/calcite-ui-icons/. | `string` | `plus` | | ||
| `label` | `label` | Label of the fab, exposed on hover. If no label is provided, the label inherits what's provided for the `text` prop. | `string` | `undefined` | | ||
| `loading` | `loading` | When true, content is waiting to be loaded. This state shows a busy indicator. | `boolean` | `false` | | ||
| `scale` | `scale` | Specifies the size of the fab. | `CalciteScale` | `m` | | ||
| `text` | `text` | Text that accompanies the fab icon. | `string` | `undefined` | | ||
| `textEnabled` | `text-enabled` | Indicates whether the text is displayed. | `boolean` | `false` | | ||
| `theme` | `theme` | Used to set the component's color scheme. | `"dark" or "light"` | `undefined` | | ||
|
||
## Methods | ||
|
||
### `setFocus() => Promise<void>` | ||
|
||
#### Returns | ||
|
||
Type: `Promise<void>` | ||
|
||
--- | ||
|
||
_Built with [StencilJS](https://stenciljs.com/)_ |
Oops, something went wrong.