@grayscale-dev/dragon 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -0
- package/dist/components/dui-input.d.ts +33 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +138 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Dragon UI
|
|
2
|
+
|
|
3
|
+
Framework-agnostic Web Components built with Lit. Currently includes `<dui-input>`.
|
|
4
|
+
|
|
5
|
+
**Build**
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
npm --workspace packages/ui run build
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Unit Tests**
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm --workspace packages/ui run test
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Covers value/property sync, native `input`/`change` events, form association, focus forwarding, and styling hooks.
|
|
19
|
+
|
|
20
|
+
**Usage (Vanilla)**
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<script type="module">
|
|
24
|
+
import '@grayscale-dev/dragon';
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<dui-input id="name" placeholder="Your name"></dui-input>
|
|
28
|
+
|
|
29
|
+
<script type="module">
|
|
30
|
+
const el = document.querySelector('#name');
|
|
31
|
+
el.addEventListener('input', (e) => {
|
|
32
|
+
console.log(e.currentTarget.value);
|
|
33
|
+
});
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Usage (React)**
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import '@grayscale-dev/dragon';
|
|
41
|
+
|
|
42
|
+
export function Demo() {
|
|
43
|
+
return (
|
|
44
|
+
<dui-input
|
|
45
|
+
placeholder="Email"
|
|
46
|
+
onInput={(e) => {
|
|
47
|
+
const el = e.currentTarget as HTMLInputElement & { value: string };
|
|
48
|
+
console.log(el.value);
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Usage (Vue)**
|
|
56
|
+
|
|
57
|
+
```vue
|
|
58
|
+
<script setup lang="ts">
|
|
59
|
+
import '@grayscale-dev/dragon';
|
|
60
|
+
|
|
61
|
+
function handleInput(e: Event) {
|
|
62
|
+
const el = e.currentTarget as HTMLInputElement & { value: string };
|
|
63
|
+
console.log(el.value);
|
|
64
|
+
}
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<dui-input placeholder="Email" @input="handleInput" />
|
|
69
|
+
</template>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Styling**
|
|
73
|
+
|
|
74
|
+
CSS custom properties:
|
|
75
|
+
|
|
76
|
+
- `--ui-input-padding`
|
|
77
|
+
- `--ui-input-font-size`
|
|
78
|
+
- `--ui-input-border`
|
|
79
|
+
- `--ui-input-radius`
|
|
80
|
+
- `--ui-input-bg`
|
|
81
|
+
- `--ui-input-color`
|
|
82
|
+
- `--ui-input-placeholder-color`
|
|
83
|
+
- `--ui-input-focus-ring`
|
|
84
|
+
|
|
85
|
+
Example:
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
dui-input {
|
|
89
|
+
--ui-input-padding: 0.75rem 1rem;
|
|
90
|
+
--ui-input-border: 1px solid #94a3b8;
|
|
91
|
+
--ui-input-radius: 999px;
|
|
92
|
+
--ui-input-focus-ring: 0 0 0 3px rgba(59, 130, 246, 0.35);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
dui-input::part(input) {
|
|
96
|
+
font-weight: 600;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Form Behavior**
|
|
101
|
+
|
|
102
|
+
`<dui-input>` dispatches native `input` and `change` events (bubbling + composed) and exposes a `value` property on the custom element. It also integrates with forms via the Form-Associated Custom Elements API where supported.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class DuiInput extends LitElement {
|
|
3
|
+
static readonly formAssociated = true;
|
|
4
|
+
static styles: import("lit").CSSResult;
|
|
5
|
+
value: string;
|
|
6
|
+
placeholder: string;
|
|
7
|
+
name: string;
|
|
8
|
+
disabled: boolean;
|
|
9
|
+
required: boolean;
|
|
10
|
+
type: string;
|
|
11
|
+
autocomplete?: string;
|
|
12
|
+
private inputEl?;
|
|
13
|
+
private internals?;
|
|
14
|
+
private defaultValue?;
|
|
15
|
+
constructor();
|
|
16
|
+
connectedCallback(): void;
|
|
17
|
+
updated(changed: Map<string, unknown>): void;
|
|
18
|
+
focus(options?: FocusOptions): void;
|
|
19
|
+
blur(): void;
|
|
20
|
+
formResetCallback(): void;
|
|
21
|
+
formStateRestoreCallback(state: unknown): void;
|
|
22
|
+
formDisabledCallback(disabled: boolean): void;
|
|
23
|
+
private syncFormValue;
|
|
24
|
+
private handleInput;
|
|
25
|
+
private handleChange;
|
|
26
|
+
private handleKeydown;
|
|
27
|
+
render(): import("lit-html").TemplateResult<1>;
|
|
28
|
+
}
|
|
29
|
+
declare global {
|
|
30
|
+
interface HTMLElementTagNameMap {
|
|
31
|
+
'dui-input': DuiInput;
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { css as d, LitElement as h, html as c } from "lit";
|
|
2
|
+
import { property as s, query as f, customElement as b } from "lit/decorators.js";
|
|
3
|
+
import { ifDefined as p } from "lit/directives/if-defined.js";
|
|
4
|
+
var m = Object.defineProperty, v = Object.getOwnPropertyDescriptor, i = (e, r, l, o) => {
|
|
5
|
+
for (var a = o > 1 ? void 0 : o ? v(r, l) : r, n = e.length - 1, u; n >= 0; n--)
|
|
6
|
+
(u = e[n]) && (a = (o ? u(r, l, a) : u(a)) || a);
|
|
7
|
+
return o && a && m(r, l, a), a;
|
|
8
|
+
};
|
|
9
|
+
let t = class extends h {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(), this.value = "", this.placeholder = "", this.name = "", this.disabled = !1, this.required = !1, this.type = "text", "attachInternals" in this && (this.internals = this.attachInternals());
|
|
12
|
+
}
|
|
13
|
+
connectedCallback() {
|
|
14
|
+
super.connectedCallback(), this.defaultValue === void 0 && (this.defaultValue = this.getAttribute("value") ?? ""), this.syncFormValue();
|
|
15
|
+
}
|
|
16
|
+
updated(e) {
|
|
17
|
+
(e.has("value") || e.has("disabled")) && this.syncFormValue();
|
|
18
|
+
}
|
|
19
|
+
focus(e) {
|
|
20
|
+
this.inputEl?.focus(e);
|
|
21
|
+
}
|
|
22
|
+
blur() {
|
|
23
|
+
this.inputEl?.blur();
|
|
24
|
+
}
|
|
25
|
+
formResetCallback() {
|
|
26
|
+
this.value = this.defaultValue ?? "";
|
|
27
|
+
}
|
|
28
|
+
formStateRestoreCallback(e) {
|
|
29
|
+
typeof e == "string" && (this.value = e);
|
|
30
|
+
}
|
|
31
|
+
formDisabledCallback(e) {
|
|
32
|
+
this.disabled = e;
|
|
33
|
+
}
|
|
34
|
+
syncFormValue() {
|
|
35
|
+
if (this.internals) {
|
|
36
|
+
if (this.disabled) {
|
|
37
|
+
this.internals.setFormValue(null);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.internals.setFormValue(this.value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
handleInput(e) {
|
|
44
|
+
e.stopPropagation();
|
|
45
|
+
const r = e.target;
|
|
46
|
+
this.value = r.value, this.dispatchEvent(new Event("input", { bubbles: !0, composed: !0 }));
|
|
47
|
+
}
|
|
48
|
+
handleChange(e) {
|
|
49
|
+
e.stopPropagation();
|
|
50
|
+
const r = e.target;
|
|
51
|
+
this.value = r.value, this.dispatchEvent(new Event("change", { bubbles: !0, composed: !0 }));
|
|
52
|
+
}
|
|
53
|
+
handleKeydown(e) {
|
|
54
|
+
if (e.key !== "Enter") return;
|
|
55
|
+
const r = e.target;
|
|
56
|
+
this.value = r.value, this.dispatchEvent(new Event("change", { bubbles: !0, composed: !0 }));
|
|
57
|
+
}
|
|
58
|
+
render() {
|
|
59
|
+
return c`
|
|
60
|
+
<input
|
|
61
|
+
part="input"
|
|
62
|
+
.value=${this.value}
|
|
63
|
+
.type=${this.type}
|
|
64
|
+
.name=${this.name}
|
|
65
|
+
?disabled=${this.disabled}
|
|
66
|
+
?required=${this.required}
|
|
67
|
+
placeholder=${p(this.placeholder || void 0)}
|
|
68
|
+
autocomplete=${p(this.autocomplete)}
|
|
69
|
+
@input=${this.handleInput}
|
|
70
|
+
@change=${this.handleChange}
|
|
71
|
+
@keydown=${this.handleKeydown}
|
|
72
|
+
/>
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
t.formAssociated = !0;
|
|
77
|
+
t.styles = d`
|
|
78
|
+
:host {
|
|
79
|
+
display: inline-block;
|
|
80
|
+
width: 100%;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
input {
|
|
84
|
+
box-sizing: border-box;
|
|
85
|
+
width: 100%;
|
|
86
|
+
padding: var(--ui-input-padding, 0.5rem 0.75rem);
|
|
87
|
+
font-size: var(--ui-input-font-size, 1rem);
|
|
88
|
+
border: var(--ui-input-border, 1px solid #c6ccd5);
|
|
89
|
+
border-radius: var(--ui-input-radius, 0.5rem);
|
|
90
|
+
background: var(--ui-input-bg, #ffffff);
|
|
91
|
+
color: var(--ui-input-color, #1f2937);
|
|
92
|
+
outline: none;
|
|
93
|
+
transition: box-shadow 120ms ease, border-color 120ms ease;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
input::placeholder {
|
|
97
|
+
color: var(--ui-input-placeholder-color, #9aa4b2);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
input:focus {
|
|
101
|
+
box-shadow: var(--ui-input-focus-ring, 0 0 0 3px rgba(24, 98, 255, 0.25));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
input:disabled {
|
|
105
|
+
opacity: 0.6;
|
|
106
|
+
cursor: not-allowed;
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
i([
|
|
110
|
+
s({ type: String })
|
|
111
|
+
], t.prototype, "value", 2);
|
|
112
|
+
i([
|
|
113
|
+
s({ type: String })
|
|
114
|
+
], t.prototype, "placeholder", 2);
|
|
115
|
+
i([
|
|
116
|
+
s({ type: String, reflect: !0 })
|
|
117
|
+
], t.prototype, "name", 2);
|
|
118
|
+
i([
|
|
119
|
+
s({ type: Boolean, reflect: !0 })
|
|
120
|
+
], t.prototype, "disabled", 2);
|
|
121
|
+
i([
|
|
122
|
+
s({ type: Boolean, reflect: !0 })
|
|
123
|
+
], t.prototype, "required", 2);
|
|
124
|
+
i([
|
|
125
|
+
s({ type: String, reflect: !0 })
|
|
126
|
+
], t.prototype, "type", 2);
|
|
127
|
+
i([
|
|
128
|
+
s({ type: String, reflect: !0 })
|
|
129
|
+
], t.prototype, "autocomplete", 2);
|
|
130
|
+
i([
|
|
131
|
+
f("input")
|
|
132
|
+
], t.prototype, "inputEl", 2);
|
|
133
|
+
t = i([
|
|
134
|
+
b("dui-input")
|
|
135
|
+
], t);
|
|
136
|
+
export {
|
|
137
|
+
t as DuiInput
|
|
138
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@grayscale-dev/dragon",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Framework-agnostic Web Components built with Lit.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "vite",
|
|
21
|
+
"build": "vite build && tsc -p tsconfig.build.json",
|
|
22
|
+
"preview": "vite preview",
|
|
23
|
+
"test": "web-test-runner --config web-test-runner.config.mjs"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@open-wc/testing": "^4.0.0",
|
|
27
|
+
"@types/node": "^22.10.0",
|
|
28
|
+
"@web/dev-server-esbuild": "^1.0.2",
|
|
29
|
+
"@web/test-runner": "^0.20.0",
|
|
30
|
+
"@web/test-runner-playwright": "^0.11.0",
|
|
31
|
+
"lit": "^3.2.1",
|
|
32
|
+
"typescript": "^5.5.4",
|
|
33
|
+
"vite": "^5.4.8"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"lit": "^3.0.0"
|
|
37
|
+
}
|
|
38
|
+
}
|