Skip to content

Commit 2d21c73

Browse files
committed
feat: initialize pnpm workspace and add TypeScript configuration
- Created pnpm-workspace.yaml to manage packages in the workspace. - Added tsconfig.json for TypeScript compiler options and project structure. - Introduced tsup.config.ts for building the project with support for Vue single-file components.
0 parents  commit 2d21c73

29 files changed

+4064
-0
lines changed

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
node_modules
2+
*/node_modules
3+
*.log
4+
*.env
5+
*.DS_Store
6+
*.swp
7+
*.swo
8+
.vite
9+
*/.vite
10+
dist
11+
*/dist

README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Vue Web Component Library
2+
3+
A Vue-based accessible design system with headless web components. This library provides accessible, customizable components that can be imported individually to optimize bundle size.
4+
5+
## Features
6+
7+
- 🧩 **Web Components**: Use anywhere, framework-agnostic
8+
-**Accessible**: Built with accessibility in mind
9+
- 🎨 **Customizable**: Style with CSS variables
10+
- 📦 **Tree-shakable**: Import only what you need
11+
- 🔧 **Headless**: Behavior and accessibility without opinionated styling
12+
- 🧰 **TypeScript**: Full type support
13+
14+
## Installation
15+
16+
You can install individual components or the entire library:
17+
18+
```bash
19+
# Install the entire library
20+
npm install @vue-web-component-library/components
21+
22+
# Or install individual components
23+
npm install @vue-web-component-library/button
24+
npm install @vue-web-component-library/input
25+
npm install @vue-web-component-library/icon
26+
```
27+
28+
## Usage
29+
30+
### Importing Components
31+
32+
You can import each component individually:
33+
34+
```js
35+
// Import specific components
36+
import '@vue-web-component-library/button';
37+
import '@vue-web-component-library/input';
38+
import '@vue-web-component-library/icon';
39+
40+
// Or import everything
41+
import '@vue-web-component-library/components';
42+
```
43+
44+
### Using in HTML
45+
46+
Once imported, you can use the components as HTML elements:
47+
48+
```html
49+
<!-- Button component -->
50+
<vwc-button size="md" variant="primary">Click me</vwc-button>
51+
52+
<!-- Input component -->
53+
<vwc-input
54+
label="Username"
55+
placeholder="Enter your username"
56+
helper-text="Your username must be at least 4 characters"
57+
></vwc-input>
58+
59+
<!-- Icon component -->
60+
<vwc-icon name="star" size="md" color="#FFD700"></vwc-icon>
61+
```
62+
63+
## Customizing with CSS Variables
64+
65+
All components can be customized using CSS variables:
66+
67+
```css
68+
:root {
69+
/* Button customization */
70+
--vwc-button-primary-bg: #4f46e5;
71+
--vwc-button-primary-text: white;
72+
--vwc-button-radius: 8px;
73+
74+
/* Input customization */
75+
--vwc-input-border: 2px solid #e5e7eb;
76+
--vwc-input-radius: 8px;
77+
--vwc-input-focus-border-color: #4f46e5;
78+
79+
/* Icon customization */
80+
--vwc-icon-md-size: 1.75rem;
81+
--vwc-icon-color: #4f46e5;
82+
}
83+
```
84+
85+
## Components
86+
87+
### Button
88+
89+
A customizable button component with various sizes and variants.
90+
91+
```html
92+
<vwc-button size="md" variant="primary">Click me</vwc-button>
93+
<vwc-button size="lg" variant="outline" disabled>Disabled</vwc-button>
94+
<vwc-button variant="ghost">
95+
<vwc-icon name="favorite" slot="before"></vwc-icon>
96+
With Icon
97+
</vwc-button>
98+
```
99+
100+
### Input
101+
102+
An accessible input component with label, helper text, and error handling.
103+
104+
```html
105+
<vwc-input
106+
label="Email"
107+
type="email"
108+
placeholder="Enter your email"
109+
required
110+
></vwc-input>
111+
112+
<vwc-input
113+
label="Password"
114+
type="password"
115+
error="Password must be at least 8 characters"
116+
>
117+
<vwc-icon name="lock" slot="before"></vwc-icon>
118+
</vwc-input>
119+
```
120+
121+
### Icon
122+
123+
A component for displaying Google Material Icons.
124+
125+
```html
126+
<vwc-icon name="home" size="md"></vwc-icon>
127+
<vwc-icon name="settings" color="#4f46e5"></vwc-icon>
128+
<vwc-icon name="refresh" spin></vwc-icon>
129+
```
130+
131+
## Contributing
132+
133+
Contributions are welcome! Please feel free to submit a Pull Request.
134+
135+
## License
136+
137+
MIT

package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "vue-web-component-library",
3+
"version": "0.1.0",
4+
"description": "A Vue-based accessible design system with headless web components",
5+
"private": true,
6+
"scripts": {
7+
"build": "pnpm -r build",
8+
"dev": "pnpm -r dev",
9+
"clean": "pnpm -r clean",
10+
"lint": "pnpm -r lint",
11+
"test": "pnpm -r test"
12+
},
13+
"keywords": [
14+
"vue",
15+
"web-components",
16+
"design-system",
17+
"headless",
18+
"accessible"
19+
],
20+
"author": "",
21+
"license": "MIT",
22+
"packageManager": "[email protected]",
23+
"devDependencies": {
24+
"@vitejs/plugin-vue": "^5.2.3",
25+
"@vue/compiler-sfc": "^3.5.13",
26+
"eslint": "^9.23.0",
27+
"eslint-plugin-vue": "^10.0.0",
28+
"prettier": "^3.5.3",
29+
"rimraf": "^6.0.1",
30+
"tsup": "^8.4.0",
31+
"typescript": "^5.8.2",
32+
"vite": "^6.2.3",
33+
"vite-plugin-dts": "^4.5.3",
34+
"vitest": "^3.0.9",
35+
"vue": "^3.5.13"
36+
}
37+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@vue-web-component-library/button",
3+
"version": "0.1.0",
4+
"description": "Accessible Button web component for Vue",
5+
"main": "dist/index.js",
6+
"module": "dist/index.mjs",
7+
"types": "dist/index.d.ts",
8+
"files": [
9+
"dist"
10+
],
11+
"scripts": {
12+
"build": "vite build",
13+
"dev": "vite build --watch",
14+
"clean": "rimraf dist",
15+
"lint": "eslint src --ext .ts,.vue",
16+
"test": "vitest"
17+
},
18+
"keywords": [
19+
"vue",
20+
"web-components",
21+
"button",
22+
"accessible",
23+
"headless"
24+
],
25+
"author": "",
26+
"license": "MIT",
27+
"sideEffects": false,
28+
"publishConfig": {
29+
"access": "public"
30+
},
31+
"dependencies": {
32+
"@vue-web-component-library/core": "workspace:*",
33+
"vue": "^3.5.0"
34+
}
35+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<template>
2+
<button
3+
:id="props.id"
4+
:class="['vwc-button', props.size, props.variant]"
5+
:disabled="props.disabled"
6+
:aria-disabled="props.disabled"
7+
:type="props.type"
8+
@click="$emit('click', $event)"
9+
>
10+
<slot name="before"></slot>
11+
<slot></slot>
12+
<slot name="after"></slot>
13+
</button>
14+
</template>
15+
16+
<script setup lang="ts">
17+
import { defineProps, defineEmits } from 'vue';
18+
import { BaseProps, Size, Variant } from '@vue-web-component-library/core';
19+
20+
export interface ButtonProps extends BaseProps {
21+
/**
22+
* The type of button
23+
*/
24+
type?: 'button' | 'submit' | 'reset';
25+
/**
26+
* The size of the button
27+
*/
28+
size?: Size;
29+
/**
30+
* The variant style of the button
31+
*/
32+
variant?: Variant;
33+
}
34+
35+
const props = withDefaults(defineProps<ButtonProps>(), {
36+
type: 'button',
37+
size: 'md',
38+
variant: 'primary',
39+
disabled: false,
40+
});
41+
42+
defineEmits<{
43+
/**
44+
* Emitted when button is clicked
45+
*/
46+
(e: 'click', event: MouseEvent): void;
47+
}>();
48+
</script>
49+
50+
<style>
51+
.vwc-button {
52+
display: inline-flex;
53+
align-items: center;
54+
justify-content: center;
55+
gap: var(--vwc-button-gap, 0.5rem);
56+
font-family: var(--vwc-button-font-family, system-ui, sans-serif);
57+
font-weight: var(--vwc-button-font-weight, 500);
58+
cursor: pointer;
59+
border-radius: var(--vwc-button-radius, 4px);
60+
border: var(--vwc-button-border, 1px solid transparent);
61+
padding: 0;
62+
transition: var(--vwc-button-transition, all 0.2s ease-in-out);
63+
outline: none;
64+
position: relative;
65+
text-decoration: none;
66+
}
67+
68+
.vwc-button:focus-visible {
69+
outline: var(--vwc-button-focus-outline, 2px solid currentColor);
70+
outline-offset: var(--vwc-button-focus-outline-offset, 2px);
71+
}
72+
73+
.vwc-button:disabled {
74+
opacity: var(--vwc-button-disabled-opacity, 0.5);
75+
cursor: not-allowed;
76+
}
77+
78+
/* Size variations */
79+
.vwc-button.sm {
80+
font-size: var(--vwc-button-sm-font-size, 0.875rem);
81+
padding: var(--vwc-button-sm-padding, 0.375rem 0.75rem);
82+
height: var(--vwc-button-sm-height, 2rem);
83+
}
84+
85+
.vwc-button.md {
86+
font-size: var(--vwc-button-md-font-size, 1rem);
87+
padding: var(--vwc-button-md-padding, 0.5rem 1rem);
88+
height: var(--vwc-button-md-height, 2.5rem);
89+
}
90+
91+
.vwc-button.lg {
92+
font-size: var(--vwc-button-lg-font-size, 1.125rem);
93+
padding: var(--vwc-button-lg-padding, 0.625rem 1.25rem);
94+
height: var(--vwc-button-lg-height, 3rem);
95+
}
96+
97+
/* Variant styles */
98+
.vwc-button.primary {
99+
background-color: var(--vwc-button-primary-bg, #3b82f6);
100+
color: var(--vwc-button-primary-text, white);
101+
}
102+
103+
.vwc-button.primary:hover:not(:disabled) {
104+
background-color: var(--vwc-button-primary-hover-bg, #2563eb);
105+
}
106+
107+
.vwc-button.secondary {
108+
background-color: var(--vwc-button-secondary-bg, #9ca3af);
109+
color: var(--vwc-button-secondary-text, white);
110+
}
111+
112+
.vwc-button.secondary:hover:not(:disabled) {
113+
background-color: var(--vwc-button-secondary-hover-bg, #6b7280);
114+
}
115+
116+
.vwc-button.outline {
117+
background-color: var(--vwc-button-outline-bg, transparent);
118+
color: var(--vwc-button-outline-text, #3b82f6);
119+
border-color: var(--vwc-button-outline-border, currentColor);
120+
}
121+
122+
.vwc-button.outline:hover:not(:disabled) {
123+
background-color: var(--vwc-button-outline-hover-bg, rgb(59 130 246 / 0.1));
124+
}
125+
126+
.vwc-button.ghost {
127+
background-color: var(--vwc-button-ghost-bg, transparent);
128+
color: var(--vwc-button-ghost-text, #3b82f6);
129+
border-color: var(--vwc-button-ghost-border, transparent);
130+
}
131+
132+
.vwc-button.ghost:hover:not(:disabled) {
133+
background-color: var(--vwc-button-ghost-hover-bg, rgb(59 130 246 / 0.1));
134+
}
135+
</style>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { defineCustomElement as VueDefineCustomElement } from 'vue';
2+
import ButtonComponent from './Button.ce.vue';
3+
import { defineCustomElement, COMPONENT_NAMES } from '@vue-web-component-library/core';
4+
5+
// Define the Button as a Vue custom element
6+
const ButtonElement = VueDefineCustomElement(ButtonComponent);
7+
8+
// Register as custom element if it's not already registered
9+
export const register = () => defineCustomElement(COMPONENT_NAMES.BUTTON, ButtonElement);
10+
11+
// Auto-register when loaded in a browser
12+
if (typeof window !== 'undefined') {
13+
register();
14+
}
15+
16+
export { ButtonComponent, ButtonElement };
17+
export * from './Button.ce.vue';
18+
19+
export default ButtonElement;

0 commit comments

Comments
 (0)