Skip to content

Commit

Permalink
feat(components): add content slot to card-control component (#2844)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Gfeller <[email protected]>
  • Loading branch information
oliverschuerch and gfellerph authored Mar 28, 2024
1 parent 3d7cbdf commit 1eae7c4
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 17 deletions.
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>`;

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

0 comments on commit 1eae7c4

Please sign in to comment.