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
10,787 changes: 10,612 additions & 175 deletions package-lock.json

Large diffs are not rendered by default.

30 changes: 18 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
"main": "webpack.config.js",
"type": "module",
"scripts": {
"check-prettier": "prettier --check .",
"fix-prettier": "prettier --write .",
"check-prettier": "prettier --check ./resources",
"fix-prettier": "prettier --write ./resources",
"prepare": "husky",
"lint:styles": "stylelint \"src/**/*.scss\"",
"prebuild:bundles": "npm run fix-prettier",
"build:bundles": "npm run build -w @craftcms/asset-bundles",
"prebuild": "npm run fix-prettier",
"build": "vite build",
"dev": "vite"
"dev": "vite",
"build:bundles": "npm run build -w @craftcms/asset-bundles",
"dev:bundles": "npm run dev -w @craftcms/asset-bundles",
"dev:cp": "npm run dev -w @craftcms/cp",
"build:cp": "npm run build -w @craftcms/cp",
"test:cp": "npm run test -w @craftcms/cp",
"storybook:cp": "npm run storybook -w @craftcms/cp"
},
"workspaces": [
"packages/*"
Expand All @@ -20,22 +24,21 @@
"node": ">=22"
},
"devDependencies": {
"@tailwindcss/vite": "^4.1.14",
"@total-typescript/tsconfig": "^1.0.4",
"@vitejs/plugin-vue": "^6.0.1",
"@craftcms/playwright": "file:packages/craftcms-playwright",
"@craftcms/webpack": "file:packages/craftcms-webpack",
"@playwright/test": "^1.52.0",
"@tailwindcss/vite": "^4.1.14",
"@total-typescript/tsconfig": "^1.0.4",
"@vitejs/plugin-vue": "^6.0.1",
"husky": "^9.1.7",
"lint-staged": "^16.1.6",
"lit": "^3.3.1",
"prettier": "3.1.1",
"npm-run-all": "^4.1.5",
"prettier": "3.6.2",
"stylelint": "^16.6.1",
"stylelint-config-standard": "^36.0.0",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-prettier": "^5.0.0",
"stylelint-use-logical-spec": "^5.0.1",
"tailwindcss": "^4.1.14",
"typescript": "^5.9.3",
"vite": "^7.1.9",
"vite-tsconfig-paths": "^5.1.4",
Expand All @@ -45,8 +48,11 @@
"@awesome.me/kit-ddaed3f5c5": "^1.0.41"
},
"dependencies": {
"@craftcms/cp": "file:packages/craftcms-cp",
"@inertiajs/vue3": "^2.2.7",
"laravel-vite-plugin": "^2.0.1",
"lit": "^3.3.1",
"tailwindcss": "^4.1.14",
"vue": "^3.5.22"
}
}
1 change: 1 addition & 0 deletions packages/craftcms-asset-bundles/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/dist/*
2 changes: 1 addition & 1 deletion packages/craftcms-asset-bundles/bundles/cp/dist/cp.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/craftcms-asset-bundles/bundles/cp/dist/cp.js.map

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions packages/craftcms-cp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/dist
/node_modules
/coverage

*storybook.log
storybook-static
3 changes: 3 additions & 0 deletions packages/craftcms-cp/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
scripts/plop/templates/**/*.hbs
**/dist
**/storybook-static
26 changes: 26 additions & 0 deletions packages/craftcms-cp/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type {StorybookConfig} from '@storybook/web-components-vite';

import {join, dirname} from 'path';

/**
* This function is used to resolve the absolute path of a package.
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
*/
function getAbsolutePath(value: string): any {
return dirname(require.resolve(join(value, 'package.json')));
}
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
getAbsolutePath('@chromatic-com/storybook'),
getAbsolutePath('@storybook/addon-themes'),
getAbsolutePath('@storybook/addon-docs'),
getAbsolutePath('@storybook/addon-a11y'),
getAbsolutePath('@storybook/addon-vitest'),
],
framework: {
name: getAbsolutePath('@storybook/web-components-vite'),
options: {},
},
};
export default config;
25 changes: 25 additions & 0 deletions packages/craftcms-cp/.storybook/preview.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.flex {
display: flex;
}

.items-center {
align-items: center;
}

.grid {
display: grid;
}

.gap-2 {
gap: 0.5rem;
}

.gap-4 {
gap: 1rem;
}

.icon {
display: inline-flex;
width: auto;
height: 1em;
}
67 changes: 67 additions & 0 deletions packages/craftcms-cp/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import type {
Preview,
WebComponentsRenderer,
} from '@storybook/web-components-vite';
import '../src/styles/cp.css';
import './preview.css';
import {icons} from '@lion/ui/icon.js';
import {html} from 'lit';
import {withThemeByDataAttribute} from '@storybook/addon-themes';
import {setCustomElementsManifest} from '@storybook/web-components';
import manifest from '../dist/custom-elements.json' with {type: 'json'};
import {setStorybookHelpersConfig} from '@wc-toolkit/storybook-helpers';

setStorybookHelpersConfig({
/** hides the `arg ref` label on each control */
hideArgRef: false,
/** sets the custom type reference in the Custom Elements Manifest */
typeRef: 'parsedTypes',
/** Adds a <script> tag where a `component` variable will reference the story's component */
setComponentVariable: false,
/** renders default values for attributes and CSS properties */
renderDefaultValues: false,
});

setCustomElementsManifest(manifest);

icons.addIconResolver('craft', (iconSet: string, name: string) => {
return html`<div>${iconSet} - ${name}</div>`;
});

const preview: Preview = {
parameters: {
controls: {
expanded: true,
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},

options: {
storySort: {
method: 'alphabetical',
},
},

a11y: {
// 'todo' - show a11y violations in the test UI only
// 'error' - fail CI on a11y violations
// 'off' - skip a11y checks entirely
test: 'todo',
},
},
decorators: [
withThemeByDataAttribute<WebComponentsRenderer>({
themes: {
light: 'light',
dark: 'dark',
},
defaultTheme: 'light',
attributeName: 'data-theme',
}),
],
tags: ['autodocs'],
};

export default preview;
7 changes: 7 additions & 0 deletions packages/craftcms-cp/.storybook/vitest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
import {setProjectAnnotations} from '@storybook/web-components-vite';
import * as projectAnnotations from './preview.js';

// This is an important step to apply the right configuration when testing your stories.
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
159 changes: 159 additions & 0 deletions packages/craftcms-cp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# @craftcms/cp

Web Components library for Craft CMS Control Panel UI.

## Features

- Built with [Lit](https://lit.dev/) and [@lion/ui](https://lion-web.netlify.app/)
- Comprehensive set of accessible, themeable UI components
- TypeScript support with full type definitions
- Storybook integration for component development
- Utility functions for common CP tasks (API clients, translations, formatting, etc.)

## Installation

```bash
npm install @craftcms/cp
```

## Usage

### Importing Components

```js
import '@craftcms/cp';
```

This imports all components and makes them available as custom elements with the `craft-` prefix.

### Importing Styles

```css
@import '@craftcms/cp';
```

This will import all the styles for all components. You'll have to be using some kind of bundler for this to work.

### Using Individual Components

```html
<craft-button variant="primary" size="medium"> Save </craft-button>

<craft-input label="Email Address" type="email" placeholder="you@example.com">
</craft-input>

<craft-card>
<h2>Card Title</h2>
<p>Card content goes here</p>
</craft-card>
```

### Importing Utilities

You can import utility functions directly:

```js
import {t, formatNumber, actionClient, apiClient} from '@craftcms/cp';

// Translation
const message = t('app', 'Welcome');

// Number formatting
const formatted = formatNumber(1234.56);

// API calls
const response = await apiClient.get('/api/entries');
```

Individual utilities can also be imported:

```js
import {t} from '@craftcms/cp/utilities/translate';
import {formatNumber} from '@craftcms/cp/utilities/format';
```

## Utilities

### API Clients

```js
import {actionClient, apiClient} from '@craftcms/cp';

// Controller actions
await actionClient.post('users/save-user', data);

// API endpoints
await apiClient.get('/api/entries');
```

### Translation

```js
import {t, formatMessage} from '@craftcms/cp';

t('category', 'message');
formatMessage('Hello {name}', {name: 'World'});
```

### Formatting

```js
import {formatNumber} from '@craftcms/cp';

formatNumber(1234.56); // Locale-aware number formatting
```

### Cookie Utilities

```js
import {getCookie, setCookie, deleteCookie} from '@craftcms/cp';

setCookie('name', 'value', 7); // expires in 7 days
const value = getCookie('name');
deleteCookie('name');
```

## Development

### Scripts

```bash
# Run tests
npm test

# Run tests in watch mode
npm run test:dev

# Build the package
npm run build

# Development build with watch mode
npm run dev

# Run Storybook
npm run storybook

# Build Storybook
npm run build:storybook

# Type checking
npm run check:types

# Format code
npm run format
```

### Testing

Tests are written using Vitest with browser and happy-dom support.

```bash
npm run test:coverage
```

## Peer Dependencies

- `lit` 3.x

- [Issues](https://github.com/craftcms/npm-packages/issues)
- [Repository](https://github.com/craftcms/npm-packages)
Loading
Loading