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(components): add content slot to card-control component #2844

Merged
6 changes: 6 additions & 0 deletions .changeset/two-shrimps-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@swisspost/design-system-documentation': minor
'@swisspost/design-system-components': minor
---

Added the new default slot, to allow the integration of custom HTML in the card-control component.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
--post-card-control-input-bg: #{post.$white};

flex-basis: 100%;
display: flex;
display: grid;
grid-template: 'input label icon' 'input content icon' / min-content auto min-content;
gap: 0 post.$size-mini;
padding: post.$size-regular;
background-color: var(--post-card-control-bg);
Expand All @@ -34,7 +35,7 @@
transition: background-color 100ms linear, border-color 100ms linear;

.card-control--input {
flex: 0 0 auto;
grid-area: input;
margin: post.$size-micro 0;
background-color: var(--post-card-control-input-bg);
border-color: var(--post-card-control-input-border-color) !important;
Expand All @@ -46,21 +47,28 @@
&:focus-visible {
box-shadow: none;
}
}

~ .card-control--label {
flex-grow: 2;
margin: post.$size-micro 0;
color: inherit !important;
pointer-events: none;
}
.card-control--label {
grid-area: label;
margin: post.$size-micro 0;
padding: 0;
color: inherit !important;
pointer-events: none;
transition-duration: 100ms;
}

.card-control--description {
grid-area: label;
font-size: 0.75rem;
}

.card-control--content {
grid-area: content;
}

.card-control--icon {
flex: 0 0 auto;
grid-area: icon;
width: post.$size-big;
height: post.$size-big;
pointer-events: none;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ let cardControlIds = 0;
/**
* @class PostCardControl - representing a stencil component
*
* @slot icon - Content to place in the named `icon` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Inline-level_content" target="_blank">inline content</a>.<br>It is only meant for <code>img</code> or <code>svg</code> elements and overrides the `icon` property.</p>
* @slot default - Content to place into the `default` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Block-level_contentt" target="_blank">block content</a>.<p className="alert alert-sm alert-warning">Even if it is generally possible, we do not recommend using interactive elements in this slot because the background of the card control is clickable.<br/>This can lead to confusion when the hit box of nested interactive controls is not clearly separated from the background, is invalid HTML and click events bubbling up to the card control will unexpectedly toggle it if they're not captured.<br/>More info: <a href="https://accessibilityinsights.io/info-examples/web/nested-interactive/">https://accessibilityinsights.io/info-examples/web/nested-interactive/</a></p>
* @slot icon - To insert a custom icon into the named `icon` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Inline-level_content" target="_blank">inline content</a>.<p className="alert alert-sm alert-info">It is only meant for <code>img</code> or <code>svg</code> elements and overrides the `icon` property.</p>
*/
@Component({
tag: 'post-card-control',
Expand Down Expand Up @@ -367,6 +368,7 @@ export class PostCardControl {
name={this.name}
value={this.value}
checked={this.checked}
aria-describedby={`${this.controlId}_label ${this.controlId}_content`}
aria-disabled={this.disabled}
aria-invalid={this.validity === 'false'}
onClick={this.controlClickHandler}
Expand All @@ -377,7 +379,11 @@ export class PostCardControl {
onKeyDown={this.controlKeyDownHandler}
/>

<label htmlFor={this.controlId} class="card-control--label form-check-label">
<label
id={`${this.controlId}_label`}
htmlFor={this.controlId}
class="card-control--label form-check-label"
>
{this.label}
{this.description ? (
<div class="card-control--description">{this.description}</div>
Expand All @@ -387,6 +393,10 @@ export class PostCardControl {
<div class="card-control--icon">
<slot name="icon">{this.icon ? <post-icon name={this.icon}></post-icon> : null}</slot>
</div>

<div id={`${this.controlId}_content`} class="card-control--content">
<slot></slot>
</div>
</div>
</Host>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ Type: `Promise<void>`

## Slots

| Slot | Description |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"icon"` | Content to place in the named `icon` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Inline-level_content" target="_blank">inline content</a>.<br>It is only meant for <code>img</code> or <code>svg</code> elements and overrides the `icon` property.</p> |
| Slot | Description |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `"default"` | Content to place into the `default` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Block-level_contentt" target="_blank">block content</a>.<p className="alert alert-sm alert-warning">Even if it is generally possible, we do not recommend using interactive elements in this slot because the background of the card control is clickable.<br/>This can lead to confusion when the hit box of nested interactive controls is not clearly separated from the background, is invalid HTML and click events bubbling up to the card control will unexpectedly toggle it if they're not captured.<br/>More info: <a href="https://accessibilityinsights.io/info-examples/web/nested-interactive/">https://accessibilityinsights.io/info-examples/web/nested-interactive/</a></p> |
| `"icon"` | To insert a custom icon into the named `icon` slot.<p>Markup accepted: <a href="https://developer.mozilla.org/en-US/docs/Glossary/Inline-level_content" target="_blank">inline content</a>.<p className="alert alert-sm alert-info">It is only meant for <code>img</code> or <code>svg</code> elements and overrides the `icon` property.</p> |


## Dependencies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The `<post-card-control>` element is part of the `@swisspost/design-system-compo

## Examples

### On dark background
### Dark backgrounds

<Canvas of={CardControlStories.DarkBackground}/>

Expand All @@ -35,6 +35,17 @@ If this is not enough, you can also use the named `icon` slot and add your very

<Canvas of={CardControlStories.CustomIcon} />

### Custom content

If you need to add other content to the component, you can use the default slot to do so.

<div className="alert alert-md alert-warning">
<p className="alert-heading">Even if it is generally possible, we do not recommend using interactive elements in this slot because the background of the card control is clickable.</p>
<p>This can lead to confusion when the hit box of nested interactive controls is not clearly separated from the background, is invalid HTML and click events bubbling up to the card control will unexpectedly toggle it if they're not captured. More info: <a href="https://accessibilityinsights.io/info-examples/web/nested-interactive/">https://accessibilityinsights.io/info-examples/web/nested-interactive/</a></p>
</div>

<Canvas of={CardControlStories.CustomContent} />

### Form Integration

You can use the component directly in your forms, the control value will be available in the `FormData` of the surrounding `<form>` element, just as you are used to from native input elements.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const meta: MetaComponent = {
'disabled': '',
'validity': 'null',
'icon': '',
'slots-default': '',
'slots-icon': '',
},
argTypes: {
Expand Down Expand Up @@ -53,6 +54,18 @@ const meta: MetaComponent = {
},
},
},
'slots-default': {
name: 'default',
control: {
type: 'text',
},
},
'slots-icon': {
name: 'icon',
control: {
type: 'text',
},
},
'method-groupReset': {
table: {
disable: true,
Expand All @@ -69,7 +82,8 @@ export const Default: Story = {
render: (args: Args) => {
const [, updateArgs] = useArgs();

const icon = html`<span slot="icon">${unsafeHTML(args['slots-icon'])}</span> `;
const content = html`${unsafeHTML(args['slots-default'])}`;
const icon = html`<span slot="icon">${unsafeHTML(args['slots-icon'])}</span>`;
gfellerph marked this conversation as resolved.
Show resolved Hide resolved

return html`
<post-card-control
Expand All @@ -86,7 +100,7 @@ export const Default: Story = {
@input="${(e: any) => updateArgs({ checked: e.detail.state })}"
@change="${(e: any) => updateArgs({ checked: e.detail.state })}"
>
${args['slots-icon'] ? icon : null}
${args['slots-default'] ? content : null} ${args['slots-icon'] ? icon : null}
</post-card-control>
`;
},
Expand Down Expand Up @@ -126,6 +140,13 @@ export const DarkBackground: Story = {
render: Default.render,
};

export const CustomContent: Story = {
args: {
'slots-default': '<ul class="mb-0"><li>List item</li><li>List item</li><li>List item</li></ul>',
},
render: Default.render,
};

export const CustomIcon: Story = {
args: {
'slots-icon':
Expand Down
Loading