standards-ui
Version:
A foundational design system built with native Web Components. Includes comprehensive TypeScript types, JSDoc documentation, and component examples.
180 lines (153 loc) • 5.81 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: ds-card.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: ds-card.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @file ds-card.js
* @summary A custom Web Component for displaying content in a card layout, optionally as a clickable link.
* @description
* The `ds-card` component displays its content in a styled card. It can be used as a static card or as a clickable card link.
*
* - The content inside `<ds-card>...</ds-card>` is rendered via the default slot.
* - If the `href` attribute is present, the card renders as a clickable link (`<a>`) with keyboard accessibility (Enter/Space to activate).
* - If `href` is not present, the card renders as a static `<div>`.
* - The card is always focusable and accessible by keyboard.
* - Uses CSS custom properties for background, border, radius, shadow, padding, and text color.
* - The card is styled via Shadow DOM; no `part` attribute is exposed.
*
* @element ds-card
*
* @slot - The card content (title, description, etc.).
*
* @attr {string} [href] - If present, the card becomes a clickable link. Opens in a new tab.
*
* @note When `href` is present, the card is rendered as an accessible link (`role="link"`, keyboard support).
* @note When `href` is absent, the card is rendered as a static group (`role="group"`).
* @note The card is always focusable (`tabindex=0`).
* @note Uses CSS custom properties: `--ds-card-background`, `--ds-card-border-color`, `--ds-card-border-radius`, `--ds-card-shadow`, `--ds-card-padding`, `--ds-card-text-color`.
*
* @example
* <!-- Static card -->
* <ds-card>
* <h2>Card Title</h2>
* <p>Some description or content.</p>
* </ds-card>
*
* @example
* <!-- Clickable card link -->
* <ds-card href="https://example.com">
* <h2>Go to Example</h2>
* <p>This card acts as a link.</p>
* </ds-card>
*/
class DsCard extends HTMLElement {
static get observedAttributes() {
return ['href'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
this._onKeyDown = this._onKeyDown.bind(this);
}
connectedCallback() {
this.render();
if (this.hasAttribute('href')) {
this.shadowRoot.querySelector('.card-link').addEventListener('keydown', this._onKeyDown);
}
}
disconnectedCallback() {
if (this.hasAttribute('href')) {
this.shadowRoot.querySelector('.card-link').removeEventListener('keydown', this._onKeyDown);
}
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'href' && oldValue !== newValue) {
this.render();
}
}
_onKeyDown(e) {
if ((e.key === 'Enter' || e.key === ' ') && this.hasAttribute('href')) {
e.preventDefault();
this.shadowRoot.querySelector('.card-link').click();
}
}
render() {
const href = this.getAttribute('href');
const isLink = !!href;
console.log(href);
this.shadowRoot.innerHTML = `
<style>
.card-root {
display: block;
background: var(--ds-card-background, #fff) !important;
border: 1px solid var(--ds-card-border-color, #e0e0e0) !important;
border-radius: var(--ds-card-border-radius, 12px) !important;
box-shadow: var(--ds-card-shadow, 0 2px 8px rgba(0,0,0,0.04)) !important;
padding: var(--ds-card-padding, 2rem 2.5rem) !important;
min-width: 200px;
min-height: 120px;
color: var(--ds-card-text-color, #222) !important;
transition: box-shadow 0.2s, border 0.2s;
outline: none;
text-decoration: none !important;
cursor: ${isLink ? 'pointer' : 'default'};
text-align: center;
}
.card-root:focus, .card-root:focus-visible, .card-root:active, .card-root:hover {
border: 1px solid var(--ds-color-primary, #007bff) !important;
box-shadow: 0 4px 16px rgba(0,123,255,0.08) !important;
}
::slotted(h2) {
margin: 0 0 0.5rem 0;
font-size: 1.3rem;
color: var(--ds-color-primary, #007bff) !important;
}
::slotted(p), ::slotted(div), ::slotted(span), ::slotted(*) {
color: #555 !important;
text-decoration: none !important;
}
</style>
${isLink ? `
<a class="card-root card-link" href="${href}" tabindex="0" role="link" target="_blank" rel="noopener">
<slot></slot>
</a>
` : `
<div class="card-root card-content" role="group" tabindex="0" aria-label="Card">
<slot></slot>
</div>
`}
`;
}
}
if (!customElements.get('ds-card')) {
customElements.define('ds-card', DsCard);
}
export default DsCard;</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BaseComponent.html">BaseComponent</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 4.0.4</a> on Wed Aug 20 2025 19:54:53 GMT-0700 (Pacific Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>