Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
28 changes: 28 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
ignorePatterns: ['dist', 'node_modules'],
plugins: ['lit-a11y', 'spellcheck'],
extends: ['@etchteam', 'plugin:lit-a11y/recommended'],
rules: {
Expand All @@ -19,6 +20,33 @@ module.exports = {
'center',
'etc',
'flexbox',
'StoryObj',
'dmd',
'obj',
'i',
'keyframes',
'srgb',
'alt',
'xl',
'xxl',
'xxxl',
'xxxxl',
'sr',
'textarea',
'Textarea',
'calc',
'unstyled',
'svg',
'colors',
'div',
'formgroup',
'dialog',
'unobserve',
'bp',
'eee',
'centers',
'centered',
'gs',
],
},
],
Expand Down
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ about: Create a report to help us improve
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
**Expected behaviour**
A clear and concise description of what you expected to happen.

**Screenshots**
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ jobs:
VALIDATE_JSX: false
VALIDATE_TSX: false
VALIDATE_TYPESCRIPT_STANDARD: false
FILTER_REGEX_EXCLUDE: preview-head.html
FILTER_REGEX_EXCLUDE: (preview-head.html|CLAUDE.md|bug_report.md)
30 changes: 15 additions & 15 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import type { Preview } from '@storybook/web-components'
import borderTokens from '../styles/tokens/border.css?raw';
import buttonTokens from '../styles/tokens/button.css?raw';
Expand Down Expand Up @@ -122,21 +122,21 @@
},
designTokenTables: {
collections: {
'diamond-radius': 'radius',
'diamond-color': 'color',
'diamond-spacing': 'spacing',
'diamond-button-gap': 'spacing',
'diamond-font-line-height': 'line-height',
'diamond-font-size': 'font-size',
'diamond-font-weight': 'font-weight',
'diamond-theme': 'color',
'diamond-button-primary': 'color',
'diamond-button-secondary': 'color',
'diamond-button-text': 'color',
'diamond-font-family': 'font-family',
'diamond-input-radio-checkbox-padding': 'spacing',
'diamond-input-padding': 'spacing',
'diamond-shadow': 'shadow',
'dmd-radius': 'radius',
'dmd-color': 'color',
'dmd-spacing': 'spacing',
'dmd-button-gap': 'spacing',
'dmd-font-line-height': 'line-height',
'dmd-font-size': 'font-size',
'dmd-font-weight': 'font-weight',
'dmd-theme': 'color',
'dmd-button-primary': 'color',
'dmd-button-secondary': 'color',
'dmd-button-text': 'color',
'dmd-font-family': 'font-family',
'dmd-input-radio-checkbox-padding': 'spacing',
'dmd-input-padding': 'spacing',
'dmd-shadow': 'shadow',
},
tokens: [
borderTokens,
Expand Down
8 changes: 4 additions & 4 deletions .storybook/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
}

docs-placeholder {
background: var(--diamond-color-grey-50);
border: dotted 1px var(--diamond-theme-border-color);
border-radius: var(--diamond-radius-sm);
background: var(--dmd-color-grey-50);
border: dotted 1px var(--dmd-theme-border-color);
border-radius: var(--dmd-radius-sm);
display: block;
padding: var(--diamond-spacing-lg);
padding: var(--dmd-spacing-lg);
text-align: left;
}
149 changes: 149 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Diamond UI is a lightweight design system built with Lit web components, design tokens, and CSS. Components use minimal JavaScript and follow the "CSS web components" methodology (see [https://etch.co/blog/css-web-components](https://etch.co/blog/css-web-components)). The library is framework-agnostic and can be installed in any web project.

**Component naming convention**: All components are prefixed with `dmd-` (abbreviated from "diamond"). For example: `dmd-grid`, `dmd-card`, `dmd-button`.

## Development Commands

### Running the project
```bash
npm start # Start Vite dev server
npm run storybook # Start Storybook on port 6006
```

### Building
```bash
npm run build # Build components and styles with Rollup
npm run build-storybook # Build Storybook static site
```

### Code quality
```bash
npm run lint:css # Lint CSS files with Stylelint
npm run lint:js # Lint JS with eslint
```

Note: There are no test scripts configured yet (`npm test` will fail).

## Architecture

### Component Categories

Components are organized into four categories under `components/`:

1. **canvas/** - Layout containers (e.g., `Card`, `Section`)
2. **composition/** - Layout and structural components (e.g., `Grid`, `FormGroup`, `Dialog`, `Hidden`)
3. **content/** - Content display components (e.g., `Icon`, `Text`, `List`, `LoadingButton`)
4. **control/** - Interactive form components (e.g., `Button`, `Input`, `RadioCheckbox`, `Link`)

### Component Types

Diamond UI uses two component approaches:

1. **Lit Components** - JavaScript web components built with Lit
- Located in `.ts` files
- Use `@customElement` decorator
- Extend `LitElement`
- Example: `Icon`, `LoadingButton`

2. **CSS Web Components** - Pure CSS components with only TypeScript interfaces
- Have a `.ts` file that ONLY exports TypeScript types/interfaces (no implementation)
- All styling and behaviour in corresponding `.css` file
- Example: `Card`, `Button`, `Grid`

### Component Structure Pattern

Each component follows this structure:

```text
components/[category]/[ComponentName]/
├── ComponentName.ts # Lit component OR type definitions only
├── ComponentName.css # Component styles (always present)
└── ComponentName.stories.ts # Storybook stories
```

**Key files:**
- `ComponentName.ts` exports an interface `[ComponentName]Attributes` defining the component's props
- All components declare global types for both vanilla HTML and React JSX usage
- React type declarations use `JSXCustomElement<T>` helper type from `types/jsx-custom-element.ts`

Example interface pattern:
```typescript
export interface CardAttributes {
border?: string | boolean;
padding?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none';
}

declare global {
interface HTMLElementTagNameMap {
'dmd-card': CardAttributes;
}
}

declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'dmd-card': JSXCustomElement<CardAttributes>;
}
}
}
```

### Design Tokens

All design tokens are defined as CSS custom properties in `styles/tokens/`:
- `border.css` - Border styles
- `button.css` - Button-specific tokens
- `color.css` - Color palette
- `font.css` - Typography
- `icon.css` - Icon sizing
- `input.css` - Form input styles
- `radius.css` - Border radius values
- `shadow.css` - Box shadows
- `spacing.css` - Spacing scale
- `theme.css` - Theme variables
- `transition.css` - Animation timings
- `wrap.css` - Container widths

Tokens can be overridden by defining CSS custom properties on `:root`.

### Build Tool

Rollup is configured to output three bundles:
1. **JavaScript components** - All `.ts` files from `components/` (excluding `.stories.ts`)
2. **Type definitions** - Generated `.d.ts` files
3. **Styles** - `diamond-ui.css` bundle that includes all component styles via PostCSS glob imports

The build:
- Uses `@rollup/plugin-typescript` for TypeScript compilation
- Uses `rollup-plugin-postcss` with `postcss-import-ext-glob` to bundle CSS
- Maintains directory structure in `dist/`
- Copies individual token files to `dist/styles/` for granular imports

### Shared Utilities

Reusable code in `lib/`:
- `pulse.ts` - Lit CSS for loading/skeleton animations
- `breakpoints.ts` - Responsive breakpoint definitions
- `css-map.ts` - Utility for mapping props to CSS classes

### Interactive Elements Pattern

When custom elements need to be interactive (clickable/tappable), wrap them in semantic HTML elements (`<a>`, `<button>`, or `<label>`).

The base CSS (`styles/base/interactive.css`) hides the styling of these wrappers when they contain:
- `dmd-card` components
- Elements with `data-interactive` attribute

This preserves accessibility while allowing visual customization.

### Theming

Diamond supports custom theming via CSS custom properties. No production themes are included by default. Theme styles are defined in `styles/themes.css`.

Theme variables follow the pattern `--dmd-theme-[property]` and can be scoped to specific components or containers.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import '@etchteam/diamond-ui/composition/Grid/Grid';
And then used in HTML (or React, Vue, Angular, etc)

```html
<diamond-grid>
<diamond-grid-item>
<dmd-grid>
<dmd-grid-item>
Grid content
</diamond-grid-item>
</diamond-grid>
</dmd-grid-item>
</dmd-grid>
```

## Configure
Expand Down
38 changes: 19 additions & 19 deletions components/canvas/Card/Card.css
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
diamond-card {
background: var(--diamond-theme-background);
dmd-card {
background: var(--dmd-theme-background);
border: 0 none;
color: var(--diamond-theme-color);
color: var(--dmd-theme-color);
display: block;
padding: var(--diamond-spacing);
transition: border-color var(--diamond-transition);
padding: var(--dmd-spacing);
transition: border-color var(--dmd-transition);

&[shadow] {
box-shadow: var(--diamond-shadow);
box-shadow: var(--dmd-shadow);
}

&[muted] {
background: var(--diamond-theme-background-muted);
background: var(--dmd-theme-background-muted);
}

&[radius] {
border-radius: var(--diamond-radius);
border-radius: var(--dmd-radius);
overflow: hidden;
}

&[padding='xs'] {
padding: var(--diamond-spacing-xs);
padding: var(--dmd-spacing-xs);
}

&[padding='sm'] {
padding: var(--diamond-spacing-sm);
padding: var(--dmd-spacing-sm);
}

&[padding='lg'] {
padding: var(--diamond-spacing-lg);
padding: var(--dmd-spacing-lg);
}

&[padding='xl'] {
padding: var(--diamond-spacing-xl);
padding: var(--dmd-spacing-xl);
}

&[padding='fluid-sm'] {
padding: var(--diamond-spacing-fluid-sm);
padding: var(--dmd-spacing-fluid-sm);
}

&[padding='fluid'] {
padding: var(--diamond-spacing-fluid);
padding: var(--dmd-spacing-fluid);
}

&[padding='fluid-lg'] {
padding: var(--diamond-spacing-fluid-lg);
padding: var(--dmd-spacing-fluid-lg);
}

&[padding='none'] {
padding: 0;
}

&[border] {
border: 1px solid var(--diamond-theme-border-color);
border: 1px solid var(--dmd-theme-border-color);
}

@media (hover: hover) {
&[border][href]:hover {
border-color: var(--diamond-theme-border-color-hover);
border-color: var(--dmd-theme-border-color-hover);
}
}
}
Expand All @@ -66,8 +66,8 @@ button,
a {
&:hover,
&:focus-visible {
diamond-card {
border-color: var(--diamond-theme-border-color-hover);
dmd-card {
border-color: var(--dmd-theme-border-color-hover);
}
}
}
Loading