kolibri-design-system
kolibri-design-system copied to clipboard
Implement BaseCard
Blocks
- #530
Summary
Implement BaseCard, a helper private component that will be used by the public KCard component. Please see #528 first.
Markup requirements
- The outermost element is
<li> <a>(generated from the<router-link>) is placed inside the heading element and the title is inside the link- Contains the heading element and it is placed above all its siblings that will be passed down from
KCardvia the default slot
<li>
<h[2-6]>
<a href="/resource">Resource</a>
</h[2-6]>
<slot>
</li>
This ensures that no matter of how we refactor the parent component KCard in the future, during the process we won't mingle new updates with basic a11y criteria related to card list, heading placement, and link that need to be satisfied under all circumstances. In a way, one of the functions of the BaseCard is to 'protect' them.
Style requirements
- Doesn't have set width/height (this will be controlled from
KCardor card grid) - Even though the whole card is not wrapped in the link, the whole card area is clickable and has the pointer cursor style
- Has focus ring on focus utilizing our
$coreOutline(see "Keyboard navigation"). Even though the whole card is not wrapped in the link, the focus ring still needs to show around the whole card area.
- Even though the whole area is clickable, text content is still selectable
- Has shadow styles
- Has the same hover style as the one used for the current Kolibri cards
- Has rounded corners
Visit the Figma designs to retrieve some of the related CSS styles.
Interface
Props
| Name | Description | Type | Required | Default |
|---|---|---|---|---|
to |
Router-link object that enables user navigation to the intended route. | Object |
true |
- |
title |
Sets the value of the title text. A simpler alternative to the title slot. |
String |
false |
null |
| titleLines | A number of lines a title text is truncated to. | Number | false | 2 |
headingLevel |
A level of the heading element (<h2>-<h6>) wrapping a title text. Supported values: 2-6. |
Number |
true |
- |
Slots
| Name | Description |
|---|---|
default |
Contents of the card except its title. |
title |
The title contents. It should not contain a heading element. An alternative to the title prop. |
Events
| Name | Description |
|---|---|
focus |
Emitted when the card element has received focus. |
hover |
Emitted when the mouse pointer enters or leaves the card element |
Acceptance criteria
- [ ] Conforms fully to the specification above
- [ ] Is not exposed publicly and doesn't have a documentation page
- [ ] Contains validation to check that
titleprop or slot has been used, throwing an error if neither is provided
Guidance
Using these particular techniques is not required, just a few tips that may help:
Existing code
In kolibri/kolibri/plugins/learn/assets/src/views/cards/, you can find lots of code for current cards in Kolibri. I wouldn't recommend it when it comes to markup and architecture since our first cards aren't very consistent and accessible (KCard is here to solve that). However, it may be useful for pulling out pieces of logic that would still be useful rather then re-implementing it. One example wold be existing styles for :hover state in CardLink.
Hover and focus
:focus-within may be helpful for implementing focus and hover styles around the whole card area
- MDN
:focus-within - See an example in Inclusive Components: Cards ("Affordance" section)
Selectable textual content
To make textual content selectable within the whole clickable card area, "Inclusive Components: Cards ("The redundant click event" section) offers a technique that may serve as inspiration for a Vue based solution:
We need to detect how long the user is taking between mousedown and mouseup and suppress the event if it's "likely to be selecting text" territory.
const cards = document.querySelectorAll('.card');
Array.prototype.forEach.call(cards, card => {
let down, up, link = card.querySelector('h2 a');
card.onmousedown = () => down = +new Date();
card.onmouseup = () => {
up = +new Date();
if ((up - down) < 200) {
link.click();
}
}
});
Hi! I would like to work on this issue if this is available to external contributors.
Hi @EshaanAgg, thank you - there is already a team member who will work on this (and other issues from this group)