Skip to content

Commit

Permalink
feat(ui-shell): support button tooltip in HeaderGlobalAction (#1894)
Browse files Browse the repository at this point in the history
Closes #1893
  • Loading branch information
spburtsev authored Mar 8, 2024
1 parent 0405ede commit d8bc651
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 90 deletions.
9 changes: 4 additions & 5 deletions COMPONENT_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ export type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584;
| size | No | <code>let</code> | No | <code>"default" &#124; "field" &#124; "small" &#124; "lg" &#124; "xl"</code> | <code>"default"</code> | Specify the size of button |
| expressive | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to use Carbon's expressive typesetting |
| isSelected | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to enable the selected state for an icon-only, ghost button |
| icon | No | <code>let</code> | No | <code>typeof import("svelte").SvelteComponent<any></code> | <code>undefined</code> | Specify the icon to render |
| icon | No | <code>let</code> | No | <code>typeof import("svelte").SvelteComponent<any></code> | <code>undefined</code> | Specify the icon to render<br />Alternatively, use the named slot "icon" (e.g., `&lt;Icon slot="icon" size="{20}" /&gt;`) |
| iconDescription | No | <code>let</code> | No | <code>string</code> | <code>undefined</code> | Specify the ARIA label for the button icon |
| tooltipAlignment | No | <code>let</code> | No | <code>"start" &#124; "center" &#124; "end"</code> | <code>"center"</code> | Set the alignment of the tooltip relative to the icon.<br />Only applies to icon-only buttons |
| tooltipPosition | No | <code>let</code> | No | <code>"top" &#124; "right" &#124; "bottom" &#124; "left"</code> | <code>"bottom"</code> | Set the position of the tooltip relative to the icon |
Expand All @@ -395,6 +395,7 @@ export type BreakpointValue = 320 | 672 | 1056 | 1312 | 1584;
| Slot name | Default | Props | Fallback |
| :-------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------- | :------- |
| -- | Yes | <code>{ props: { role: "button"; type?: string; tabindex: any; disabled: boolean; href?: string; class: string; [key: string]: any; } } </code> | -- |
| icon | No | -- | -- |

### Events

Expand Down Expand Up @@ -1666,15 +1667,13 @@ None.

| Prop name | Required | Kind | Reactive | Type | Default value | Description |
| :-------- | :------- | :--------------- | :------- | --------------------------------------------------------- | ---------------------- | --------------------------------------------- |
| ref | No | <code>let</code> | Yes | <code>null &#124; HTMLButtonElement</code> | <code>null</code> | Obtain a reference to the HTML button element |
| ref | No | <code>let</code> | Yes | <code>HTMLButtonElement</code> | <code>null</code> | Obtain a reference to the HTML button element |
| isActive | No | <code>let</code> | No | <code>boolean</code> | <code>false</code> | Set to `true` to use the active variant |
| icon | No | <code>let</code> | No | <code>typeof import("svelte").SvelteComponent<any></code> | <code>undefined</code> | Specify the icon to render |

### Slots

| Slot name | Default | Props | Fallback |
| :-------- | :------ | :---- | :---------------------------------------------------------------- |
| -- | Yes | -- | <code>&lt;svelte:component this="{icon}" size="{20}" /&gt;</code> |
None.

### Events

Expand Down
24 changes: 11 additions & 13 deletions docs/src/COMPONENT_API.json
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,7 @@
{
"name": "icon",
"kind": "let",
"description": "Specify the icon to render",
"description": "Specify the icon to render\nAlternatively, use the named slot \"icon\" (e.g., `<Icon slot=\"icon\" size=\"{20}\" />`)",
"type": "typeof import(\"svelte\").SvelteComponent<any>",
"isFunction": false,
"isFunctionDeclaration": false,
Expand Down Expand Up @@ -633,7 +633,8 @@
"name": "__default__",
"default": true,
"slot_props": "{ props: { role: \"button\"; type?: string; tabindex: any; disabled: boolean; href?: string; class: string; [key: string]: any; } }"
}
},
{ "name": "icon", "default": false, "slot_props": "{}" }
],
"events": [
{ "type": "forwarded", "name": "click", "element": "ButtonSkeleton" },
Expand Down Expand Up @@ -5103,7 +5104,7 @@
"name": "ref",
"kind": "let",
"description": "Obtain a reference to the HTML button element",
"type": "null | HTMLButtonElement",
"type": "HTMLButtonElement",
"value": "null",
"isFunction": false,
"isFunctionDeclaration": false,
Expand All @@ -5113,17 +5114,14 @@
}
],
"moduleExports": [],
"slots": [
{
"name": "__default__",
"default": true,
"fallback": "<svelte:component this=\"{icon}\" size=\"{20}\" />",
"slot_props": "{}"
}
],
"events": [{ "type": "forwarded", "name": "click", "element": "button" }],
"slots": [],
"events": [{ "type": "forwarded", "name": "click", "element": "Button" }],
"typedefs": [],
"rest_props": { "type": "Element", "name": "button" }
"rest_props": { "type": "InlineComponent", "name": "Button" },
"extends": {
"interface": "ButtonProps",
"import": "\"../Button/Button.svelte\""
}
},
{
"moduleName": "HeaderNav",
Expand Down
50 changes: 14 additions & 36 deletions docs/src/pages/framed/UIShell/HeaderUtilities.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
import {
Header,
HeaderUtilities,
HeaderAction,
HeaderGlobalAction,
HeaderPanelLinks,
HeaderPanelDivider,
HeaderPanelLink,
SideNav,
SideNavItems,
SideNavMenu,
Expand All @@ -18,50 +14,32 @@
Row,
Column,
} from "carbon-components-svelte";
import Logout from "carbon-icons-svelte/lib/Logout.svelte";
import SettingsAdjust from "carbon-icons-svelte/lib/SettingsAdjust.svelte";
import UserAvatarFilledAlt from "carbon-icons-svelte/lib/UserAvatarFilledAlt.svelte";
let isSideNavOpen = false;
let isOpen1 = false;
let isOpen2 = false;
</script>

<Header company="IBM" platformName="Carbon Svelte" bind:isSideNavOpen>
<svelte:fragment slot="skip-to-content">
<SkipToContent />
</svelte:fragment>
<HeaderUtilities>
<HeaderGlobalAction aria-label="Settings" icon="{SettingsAdjust}" />
<HeaderAction
bind:isOpen="{isOpen1}"
<HeaderGlobalAction
iconDescription="Settings"
tooltipAlignment="start"
icon="{SettingsAdjust}"
/>
<HeaderGlobalAction
iconDescription="Profile"
icon="{UserAvatarFilledAlt}"
closeIcon="{UserAvatarFilledAlt}"
>
<HeaderPanelLinks>
<HeaderPanelDivider>Switcher subject 1</HeaderPanelDivider>
<HeaderPanelLink>Switcher item 1</HeaderPanelLink>
<HeaderPanelLink>Switcher item 2</HeaderPanelLink>
<HeaderPanelLink>Switcher item 3</HeaderPanelLink>
<HeaderPanelLink>Switcher item 4</HeaderPanelLink>
<HeaderPanelDivider>Switcher subject 2</HeaderPanelDivider>
<HeaderPanelLink>Switcher item 1</HeaderPanelLink>
<HeaderPanelLink>Switcher item 2</HeaderPanelLink>
<HeaderPanelDivider>Switcher subject 3</HeaderPanelDivider>
<HeaderPanelLink>Switcher item 1</HeaderPanelLink>
</HeaderPanelLinks>
</HeaderAction>
<HeaderAction bind:isOpen="{isOpen2}">
<HeaderPanelLinks>
<HeaderPanelDivider>Switcher subject 1</HeaderPanelDivider>
<HeaderPanelLink>Switcher item 1</HeaderPanelLink>
<HeaderPanelDivider>Switcher subject 2</HeaderPanelDivider>
<HeaderPanelLink>Switcher item 1</HeaderPanelLink>
<HeaderPanelLink>Switcher item 2</HeaderPanelLink>
<HeaderPanelLink>Switcher item 3</HeaderPanelLink>
<HeaderPanelLink>Switcher item 4</HeaderPanelLink>
<HeaderPanelLink>Switcher item 5</HeaderPanelLink>
</HeaderPanelLinks>
</HeaderAction>
/>
<HeaderGlobalAction
iconDescription="Log out"
tooltipAlignment="end"
icon="{Logout}"
/>
</HeaderUtilities>
</Header>

Expand Down
50 changes: 36 additions & 14 deletions src/Button/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
/**
* Specify the icon to render
* Alternatively, use the named slot "icon" (e.g., `<Icon slot="icon" size="{20}" />`)
*
* @type {typeof import("svelte").SvelteComponent<any>}
*/
export let icon = undefined;
Expand Down Expand Up @@ -85,7 +87,12 @@
$: if (ctx && ref) {
ctx.declareRef(ref);
}
$: hasIconOnly = icon && !$$slots.default;
$: hasIconOnly = (icon || $$slots.icon) && !$$slots.default;
$: iconProps = {
"aria-hidden": "true",
class: "bx--btn__icon",
"aria-label": iconDescription,
};
$: buttonProps = {
type: href && !disabled ? undefined : type,
tabindex,
Expand Down Expand Up @@ -158,12 +165,20 @@
{#if hasIconOnly}
<span class:bx--assistive-text="{true}">{iconDescription}</span>
{/if}
<slot /><svelte:component
this="{icon}"
aria-hidden="true"
class="bx--btn__icon"
aria-label="{iconDescription}"
/>
<slot />
{#if $$slots.icon}
<slot
name="icon"
style="{hasIconOnly ? 'margin-left: 0' : undefined}"
{...iconProps}
/>
{:else if icon}
<svelte:component
this="{icon}"
style="{hasIconOnly ? 'margin-left: 0' : undefined}"
{...iconProps}
/>
{/if}
</a>
{:else}
<button
Expand All @@ -179,12 +194,19 @@
{#if hasIconOnly}
<span class:bx--assistive-text="{true}">{iconDescription}</span>
{/if}
<slot /><svelte:component
this="{icon}"
aria-hidden="true"
class="bx--btn__icon"
style="{hasIconOnly ? 'margin-left: 0' : undefined}"
aria-label="{iconDescription}"
/>
<slot />
{#if $$slots.icon}
<slot
name="icon"
style="{hasIconOnly ? 'margin-left: 0' : undefined}"
{...iconProps}
/>
{:else if icon}
<svelte:component
this="{icon}"
style="{hasIconOnly ? 'margin-left: 0' : undefined}"
{...iconProps}
/>
{/if}
</button>
{/if}
33 changes: 20 additions & 13 deletions src/UIShell/HeaderGlobalAction.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<script>
/**
* @extends {"../Button/Button.svelte"} ButtonProps
*/
/** Set to `true` to use the active variant */
export let isActive = false;
Expand All @@ -8,19 +12,22 @@
*/
export let icon = undefined;
/** Obtain a reference to the HTML button element */
/** Obtain a reference to the HTML button element
* @type {HTMLButtonElement}
*/
export let ref = null;
import Button from "../Button/Button.svelte";
$: buttonClass = [
"bx--header__action",
isActive && " bx--header__action--active",
$$restProps.class,
]
.filter(Boolean)
.join(" ");
</script>

<button
type="button"
bind:this="{ref}"
class:bx--header__action="{true}"
class:bx--header__action--active="{isActive}"
{...$$restProps}
on:click
>
<slot>
<svelte:component this="{icon}" size="{20}" />
</slot>
</button>
<Button bind:ref {...$$restProps} class="{buttonClass}" on:click>
<svelte:component this="{icon}" slot="icon" size="{20}" />
</Button>
2 changes: 1 addition & 1 deletion tests/HeaderUtilities.test.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
<SkipToContent />
</div>
<HeaderUtilities>
<HeaderGlobalAction aria-label="Settings" icon="{SettingsAdjust}" />
<HeaderGlobalAction iconDescription="Settings" icon="{SettingsAdjust}" />
<HeaderAction
bind:isOpen
on:open
Expand Down
2 changes: 2 additions & 0 deletions types/Button/Button.svelte.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export interface ButtonProps extends ButtonSkeletonProps, RestProps {

/**
* Specify the icon to render
* Alternatively, use the named slot "icon" (e.g., `<Icon slot="icon" size="{20}" />`)
* @default undefined
*/
icon?: typeof import("svelte").SvelteComponent<any>;
Expand Down Expand Up @@ -132,5 +133,6 @@ export default class Button extends SvelteComponentTyped<
[key: string]: any;
};
};
icon: {};
}
> {}
12 changes: 4 additions & 8 deletions types/UIShell/HeaderGlobalAction.svelte.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import type { SvelteComponentTyped } from "svelte";
import type { SvelteHTMLElements } from "svelte/elements";
import type { ButtonProps } from "../Button/Button.svelte";

type RestProps = SvelteHTMLElements["button"];

export interface HeaderGlobalActionProps extends RestProps {
export interface HeaderGlobalActionProps extends ButtonProps {
/**
* Set to `true` to use the active variant
* @default false
Expand All @@ -20,13 +18,11 @@ export interface HeaderGlobalActionProps extends RestProps {
* Obtain a reference to the HTML button element
* @default null
*/
ref?: null | HTMLButtonElement;

[key: `data-${string}`]: any;
ref?: HTMLButtonElement;
}

export default class HeaderGlobalAction extends SvelteComponentTyped<
HeaderGlobalActionProps,
{ click: WindowEventMap["click"] },
{ default: {} }
{}
> {}

0 comments on commit d8bc651

Please sign in to comment.