@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 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
+ }
@@ -0,0 +1,2 @@
1
+ import './components/dui-input.js';
2
+ export { DuiInput } from './components/dui-input.js';
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
+ }