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(pie-button): DSW-2305 add tag prop which lets the button render as an anchor #1703

Merged
merged 18 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/curly-shrimps-smash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"pie-docs": patch
---

[Added] - documentation for when buttons and links act like one another
6 changes: 6 additions & 0 deletions .changeset/fifty-panthers-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@justeattakeaway/pie-button": minor
---

[Added] - tag prop which lets the button render as an anchor tag
[Added] - `href`, `rel` and `target` props which can be passed to the anchor element
7 changes: 7 additions & 0 deletions .changeset/little-ligers-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"pie-storybook": patch
---

[Added] - anchor story for pie-button
[Added] - new props to button stories
[Changed] - exclude some button props from stories where they aren't relevant
5 changes: 5 additions & 0 deletions .changeset/rich-gorillas-agree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@justeattakeaway/pie-webc-testing": patch
---

[Changed] - update PropObject type to adhere more closely to component interface
24 changes: 18 additions & 6 deletions apps/pie-docs/src/components/button/overview/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ Buttons serve a wide range of purposes in user interfaces, such as submitting fo
do: {
type: usageTypes.text,
items: [
"Use Buttons when you need to direct the user to an action.",
"When pairing Buttons, use the same sized Buttons together."

"Use buttons when you need to direct the user to an action.",
"When pairing buttons, use the same sized buttons together.",
"When multiple buttons are used within the same component or page, ensure that there is a clear hierarchy of actions."
]
},
dont: {
type: usageTypes.text,
items: [
"Do not use buttons as navigational elements. Instead, use links when the desired action is to take the user to a new page."
"Don't mix button sizes when buttons are used together in a pair."
]
}
} %}
Expand Down Expand Up @@ -87,7 +87,7 @@ Secondary buttons serve as supplementary options for secondary, non-essential ac

### Outline

Outline buttons are designed to provide increased emphasis compared to ghost buttons, owing to their visible stroke. They can be utilized either as standalone buttons or in combination with a primary button.
Outline buttons are designed to provide increased emphasis compared to ghost buttons, owing to their visible stroke. They can be utilised either as standalone buttons or in combination with a primary button.

{% contentPageImage {
src:"../../../assets/img/components/button/variation-outline.svg",
Expand Down Expand Up @@ -257,11 +257,23 @@ Button sizes can adapt to different screen widths, like wide and narrow views, b

---

## Behaviours

### Buttons that act as links

This is available when a button needs to be used as a navigational element to direct users to a new page or location.

Use these with caution - dictation software users may not be able to properly identify these actions, since they are semantically links, even though they may look like buttons.

---

## Content

### Labels

Button labels should clearly indicate the action of the Button and describe what will occur once the user clicks the Button. Use active verbs, such as Add or Delete. For sets of buttons, use specific labels, such as Save or Discard, instead of using OK and Cancel. This is particularly helpful when the user is confirming an action. Use sentence-style capitalisation (only the first world in a phrase and any proper nouns capitalised).
Button labels should clearly indicate the action of the Button and describe what will occur once the user clicks the Button. Use active verbs, such as Add or Delete. For sets of buttons, use specific labels, such as Save or Discard, instead of using OK and Cancel. This is particularly helpful when the user is confirming an action.

Use sentence-style capitalisation (only the first world in a phrase and any proper nouns capitalised).

---

Expand Down
20 changes: 12 additions & 8 deletions apps/pie-docs/src/components/link/overview/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ Links are often used to connect various pages, sections, or external resources,
dont: {
type: usageTypes.text,
items: [
"Don’t use standalone links as calls to action. Use buttons instead.",
"Don’t use standalone links for actions that will change elements in a screen. Use buttons instead."
"Don't use the reversed styling when surrounded by regular text, as it will get lost."
]
}
} %}
Expand Down Expand Up @@ -201,11 +200,21 @@ You can use icons to reinforce the action that will take place when the user int

---

## Behaviours

### Links that act as buttons

This is available when a link needs to be used as a call to action that triggers an action for the users.

Use these with caution - dictation software users may not be able to properly identify these actions, since they are semantically buttons, even though they may look like links.

---

## Content

- Be mindful of which words in a paragraph you use for your links. Make sure the words you convert into links are directly related to the content that the link will lead you to.

- Use sentence-style capitalization (only the first word in a phrase and any proper nouns capitalized).
- Use sentence-style capitalisation (only the first word in a phrase and any proper nouns capitalised).

---

Expand Down Expand Up @@ -372,11 +381,6 @@ Here are some examples of links in right-to-left context:

## Resources

{% notification {
type: "warning",
message: "We’re currently working on updating our Link documentation, please see the resources below."
} %}

{% resourceTable {
componentName: 'Link'
} %}
129 changes: 106 additions & 23 deletions apps/pie-storybook/stories/pie-button.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { ifDefined } from 'lit/directives/if-defined.js';
/* eslint-disable import/no-duplicates */
import '@justeattakeaway/pie-button';
import {
ButtonProps as ButtonPropsBase, iconPlacements, sizes, types, variants, responsiveSizes, defaultProps,
type ButtonProps as ButtonPropsBase,
defaultProps, iconPlacements, responsiveSizes, sizes, types, variants,
} from '@justeattakeaway/pie-button';
/* eslint-enable import/no-duplicates */
import '@justeattakeaway/pie-icons-webc/dist/IconPlusCircle.js';

import { createStory, type TemplateFunction, sanitizeAndRenderHTML } from '../utilities';
import { StoryMeta, SlottedComponentProps } from '../types';
import { type StoryMeta, type SlottedComponentProps } from '../types';

type ButtonProps = SlottedComponentProps<ButtonPropsBase>;
type ButtonStoryMeta = StoryMeta<ButtonProps>;
Expand All @@ -25,6 +26,15 @@ const buttonStoryMeta: ButtonStoryMeta = {
title: 'Button',
component: 'pie-button',
argTypes: {
tag: {
description: 'Choose the HTML element that will be used to render the button.<br>For this story, the prop has the value of `button`. See the Anchor story to interact with the component when this prop has a value of `a`.',
xander-marjoram marked this conversation as resolved.
Show resolved Hide resolved
control: {
disable: true,
},
defaultValue: {
summary: 'button',
},
},
size: {
description: 'Set the size of the button.',
control: 'select',
Expand All @@ -34,7 +44,7 @@ const buttonStoryMeta: ButtonStoryMeta = {
},
},
type: {
description: 'Set the type of the button.',
description: 'Set the type of the button.<br><br>Set this to `submit` to reveal more controls relating to form submission.',
control: 'select',
options: types,
defaultValue: {
Expand Down Expand Up @@ -76,7 +86,7 @@ const buttonStoryMeta: ButtonStoryMeta = {
},
},
isResponsive: {
description: 'If `true`, uses the next larger size on wide viewports',
description: 'If `true`, uses the next larger size on wide viewports.<br><br>Set this to `true` to show the `responsiveSize` control.',
control: 'boolean',
defaultValue: {
summary: defaultProps.isResponsive,
Expand Down Expand Up @@ -154,6 +164,18 @@ const buttonStoryMeta: ButtonStoryMeta = {
},
if: { arg: 'isResponsive', eq: true },
},
href: {
description: 'Set the href attribute for the underlying anchor tag.',
control: 'text',
},
target: {
description: 'Set the target attribute for the underlying anchor tag.',
control: 'text',
},
rel: {
description: 'Set the rel attribute for the underlying anchor tag',
control: 'text',
},
},
args: defaultArgs,
parameters: {
Expand Down Expand Up @@ -186,26 +208,43 @@ const Template: TemplateFunction<ButtonProps> = ({
responsiveSize,
}) => html`
<pie-button
tag="button"
size="${ifDefined(size)}"
variant="${ifDefined(variant)}"
type="${ifDefined(type)}"
iconPlacement="${iconPlacement || nothing}"
iconPlacement="${ifDefined(iconPlacement)}"
?disabled="${disabled}"
?isLoading="${isLoading}"
?isFullWidth="${isFullWidth}"
?isResponsive="${isResponsive}"
name=${name || nothing}
value=${value || nothing}
responsiveSize="${responsiveSize || nothing}"
formaction=${formaction || nothing}
formenctype=${formenctype || nothing}
formmethod=${formmethod || nothing}
formtarget=${formtarget || nothing}
name=${ifDefined(name)}
value=${ifDefined(value)}
responsiveSize="${ifDefined(responsiveSize)}"
formaction=${ifDefined(formaction)}
formenctype=${ifDefined(formenctype)}
formmethod=${ifDefined(formmethod)}
formtarget=${ifDefined(formtarget)}
?formnovalidate="${formnovalidate}">
${iconPlacement ? html`<icon-plus-circle slot="icon"></icon-plus-circle>` : nothing}
${sanitizeAndRenderHTML(slot)}
</pie-button>`;

const AnchorTemplate: TemplateFunction<ButtonProps> = (props: ButtonProps) => html`
<pie-button
tag="a"
size="${ifDefined(props.size)}"
variant="${ifDefined(props.variant)}"
iconPlacement="${ifDefined(props.iconPlacement)}"
?isFullWidth="${props.isFullWidth}"
?isResponsive="${props.isResponsive}"
responsiveSize="${ifDefined(props.responsiveSize)}"
href="${ifDefined(props.href)}"
rel="${ifDefined(props.rel)}"
target="${ifDefined(props.target)}">
${props.iconPlacement ? html`<icon-plus-circle slot="icon"></icon-plus-circle>` : nothing}
${sanitizeAndRenderHTML(props.slot)}
</pie-button>`;

const FormTemplate: TemplateFunction<ButtonProps> = (props: ButtonProps) => html`
<p id="formLog" style="display: none; font-size: 2rem; color: var(--dt-color-support-positive);"></p>
<h2>Fake form</h2>
Expand Down Expand Up @@ -302,18 +341,62 @@ const createButtonStory = createStory<ButtonProps>(Template, defaultArgs);

const createButtonStoryWithForm = createStory<ButtonProps>(FormTemplate, defaultArgs);

export const Primary = createButtonStory();
export const Secondary = createButtonStory({ variant: 'secondary' });
export const Outline = createButtonStory({ variant: 'outline' }, { bgColor: 'background-subtle' });
export const Ghost = createButtonStory({ variant: 'ghost' }, { bgColor: 'background-subtle' });
export const Destructive = createButtonStory({ variant: 'destructive' });
export const DestructiveGhost = createButtonStory({ variant: 'destructive-ghost' }, { bgColor: 'background-subtle' });
export const Inverse = createButtonStory({ variant: 'inverse' }, { bgColor: 'dark (container-dark)' });
export const GhostInverse = createButtonStory({ variant: 'ghost-inverse' }, { bgColor: 'dark (container-dark)' });
export const OutlineInverse = createButtonStory({ variant: 'outline-inverse' }, { bgColor: 'dark (container-dark)' });
// For this story we simply want to test form integration with a reset and submit button. Therefore we are restricting what controls are shown.
const anchorOnlyProps : Array<keyof ButtonProps> = ['href', 'target', 'rel'];

export const Primary = createButtonStory({}, {
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Secondary = createButtonStory({ variant: 'secondary' }, {
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Outline = createButtonStory({ variant: 'outline' }, {
bgColor: 'background-subtle',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Ghost = createButtonStory({ variant: 'ghost' }, {
bgColor: 'background-subtle',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Destructive = createButtonStory({ variant: 'destructive' }, {
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const DestructiveGhost = createButtonStory({ variant: 'destructive-ghost' }, {
bgColor: 'background-subtle',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Inverse = createButtonStory({ variant: 'inverse' }, {
bgColor: 'dark (container-dark)',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const GhostInverse = createButtonStory({ variant: 'ghost-inverse' }, {
bgColor: 'dark (container-dark)',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const OutlineInverse = createButtonStory({ variant: 'outline-inverse' }, {
bgColor: 'dark (container-dark)',
controls: { exclude: ['variant', ...anchorOnlyProps] },
});

export const Anchor = createStory(AnchorTemplate, defaultArgs)({
href: '/?path=/story/button--anchor',
}, {
controls: {
// Hide button-only controls
exclude: ['type', 'disabled', 'formaction', 'formenctype', 'formmethod', 'formnovalidate', 'formtarget', 'isLoading', 'name', 'value'],
},
});

export const FormIntegration = createButtonStoryWithForm({ type: 'submit' }, {
controls: {
exclude: ['type', 'slot', 'variant', 'isFullWidth', 'iconPlacement'],
// For this story we simply want to test form integration with a reset and submit button. Therefore we are restricting what controls are shown.
exclude: ['type', 'slot', 'variant', 'isFullWidth', 'iconPlacement', ...anchorOnlyProps],
},
});
3 changes: 2 additions & 1 deletion packages/components/pie-button/src/button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
}

position: relative;
display: flex;
display: inline-flex;
jamieomaguire marked this conversation as resolved.
Show resolved Hide resolved
gap: var(--dt-spacing-b);
align-items: center;
justify-content: center;
Expand All @@ -89,6 +89,7 @@
line-height: var(--btn-line-height);
cursor: pointer;
user-select: none;
text-decoration: none;

// used to specify whether the button should be full width or not
inline-size: var(--btn-inline-size);
Expand Down
Loading
Loading