@grayscale-dev/dragon 0.1.1 → 0.1.2

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 CHANGED
@@ -24,7 +24,8 @@ Covers value/property sync, native `input`/`change` events, form association, fo
24
24
  import '@grayscale-dev/dragon';
25
25
  </script>
26
26
 
27
- <dui-input id="name" placeholder="Your name"></dui-input>
27
+ <dui-input id="name" label="Name" label-position="above"></dui-input>
28
+ <dui-input id="email" label="Email" label-position="floating"></dui-input>
28
29
 
29
30
  <script type="module">
30
31
  const el = document.querySelector('#name');
@@ -42,7 +43,8 @@ import '@grayscale-dev/dragon';
42
43
  export function Demo() {
43
44
  return (
44
45
  <dui-input
45
- placeholder="Email"
46
+ label="Email"
47
+ label-position="floating"
46
48
  onInput={(e) => {
47
49
  const el = e.currentTarget as HTMLInputElement & { value: string };
48
50
  console.log(el.value);
@@ -65,7 +67,7 @@ function handleInput(e: Event) {
65
67
  </script>
66
68
 
67
69
  <template>
68
- <dui-input placeholder="Email" @input="handleInput" />
70
+ <dui-input label="Email" label-position="floating" @input="handleInput" />
69
71
  </template>
70
72
  ```
71
73
 
@@ -97,6 +99,13 @@ dui-input::part(input) {
97
99
  }
98
100
  ```
99
101
 
102
+ **Labels**
103
+
104
+ `label` and `label-position` control the built-in label:
105
+
106
+ - `label-position="above"` (default): label sits above the field.
107
+ - `label-position="floating"`: label sits like a placeholder and floats to the top-left on focus or when the input has a value.
108
+
100
109
  **Form Behavior**
101
110
 
102
111
  `<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.
@@ -9,6 +9,8 @@ export declare class DuiInput extends LitElement {
9
9
  required: boolean;
10
10
  type: string;
11
11
  autocomplete?: string;
12
+ label: string;
13
+ labelPosition: 'floating' | 'above';
12
14
  private inputEl?;
13
15
  private internals?;
14
16
  private defaultValue?;
package/dist/index.js CHANGED
@@ -1,23 +1,23 @@
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";
1
+ import { css as h, LitElement as c, html as d } from "lit";
2
+ import { property as l, query as f, customElement as b } from "lit/decorators.js";
3
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;
4
+ var g = Object.defineProperty, m = Object.getOwnPropertyDescriptor, a = (t, i, o, n) => {
5
+ for (var r = n > 1 ? void 0 : n ? m(i, o) : i, s = t.length - 1, u; s >= 0; s--)
6
+ (u = t[s]) && (r = (n ? u(i, o, r) : u(r)) || r);
7
+ return n && r && g(i, o, r), r;
8
8
  };
9
- let t = class extends h {
9
+ let e = class extends c {
10
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());
11
+ super(), this.value = "", this.placeholder = "", this.name = "", this.disabled = !1, this.required = !1, this.type = "text", this.label = "", this.labelPosition = "above", "attachInternals" in this && (this.internals = this.attachInternals());
12
12
  }
13
13
  connectedCallback() {
14
14
  super.connectedCallback(), this.defaultValue === void 0 && (this.defaultValue = this.getAttribute("value") ?? ""), this.syncFormValue();
15
15
  }
16
- updated(e) {
17
- (e.has("value") || e.has("disabled")) && this.syncFormValue();
16
+ updated(t) {
17
+ (t.has("value") || t.has("disabled")) && this.syncFormValue();
18
18
  }
19
- focus(e) {
20
- this.inputEl?.focus(e);
19
+ focus(t) {
20
+ this.inputEl?.focus(t);
21
21
  }
22
22
  blur() {
23
23
  this.inputEl?.blur();
@@ -25,11 +25,11 @@ let t = class extends h {
25
25
  formResetCallback() {
26
26
  this.value = this.defaultValue ?? "";
27
27
  }
28
- formStateRestoreCallback(e) {
29
- typeof e == "string" && (this.value = e);
28
+ formStateRestoreCallback(t) {
29
+ typeof t == "string" && (this.value = t);
30
30
  }
31
- formDisabledCallback(e) {
32
- this.disabled = e;
31
+ formDisabledCallback(t) {
32
+ this.disabled = t;
33
33
  }
34
34
  syncFormValue() {
35
35
  if (this.internals) {
@@ -40,46 +40,86 @@ let t = class extends h {
40
40
  this.internals.setFormValue(this.value);
41
41
  }
42
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 }));
43
+ handleInput(t) {
44
+ t.stopPropagation();
45
+ const i = t.target;
46
+ this.value = i.value, this.dispatchEvent(new Event("input", { bubbles: !0, composed: !0 }));
47
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 }));
48
+ handleChange(t) {
49
+ t.stopPropagation();
50
+ const i = t.target;
51
+ this.value = i.value, this.dispatchEvent(new Event("change", { bubbles: !0, composed: !0 }));
52
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 }));
53
+ handleKeydown(t) {
54
+ if (t.key !== "Enter") return;
55
+ const i = t.target;
56
+ this.value = i.value, this.dispatchEvent(new Event("change", { bubbles: !0, composed: !0 }));
57
57
  }
58
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
- />
59
+ const t = this.label.length > 0, i = t && this.labelPosition === "floating", o = this.value.length > 0;
60
+ return d`
61
+ <div class="field ${i ? "floating" : ""}" data-has-value=${o}>
62
+ ${t ? d`<label for="input">${this.label}</label>` : null}
63
+ <input
64
+ id="input"
65
+ part="input"
66
+ .value=${this.value}
67
+ .type=${this.type}
68
+ .name=${this.name}
69
+ ?disabled=${this.disabled}
70
+ ?required=${this.required}
71
+ placeholder=${p(this.placeholder || void 0)}
72
+ autocomplete=${p(this.autocomplete)}
73
+ aria-label=${p(this.label || this.placeholder || void 0)}
74
+ @input=${this.handleInput}
75
+ @change=${this.handleChange}
76
+ @keydown=${this.handleKeydown}
77
+ />
78
+ </div>
73
79
  `;
74
80
  }
75
81
  };
76
- t.formAssociated = !0;
77
- t.styles = d`
82
+ e.formAssociated = !0;
83
+ e.styles = h`
78
84
  :host {
79
85
  display: inline-block;
80
86
  width: 100%;
81
87
  }
82
88
 
89
+ .field {
90
+ position: relative;
91
+ display: block;
92
+ width: 100%;
93
+ }
94
+
95
+ label {
96
+ display: block;
97
+ font-size: 0.875rem;
98
+ color: var(--ui-input-label-color, #475569);
99
+ margin-bottom: 0.4rem;
100
+ line-height: 1.2;
101
+ }
102
+
103
+ .field.floating label {
104
+ position: absolute;
105
+ left: var(--ui-input-floating-label-left, 0.75rem);
106
+ top: 50%;
107
+ transform: translateY(-50%);
108
+ margin: 0;
109
+ padding: 0 0.25rem;
110
+ background: var(--ui-input-bg, #ffffff);
111
+ color: var(--ui-input-placeholder-color, #9aa4b2);
112
+ pointer-events: none;
113
+ transition: transform 120ms ease, top 120ms ease, color 120ms ease;
114
+ }
115
+
116
+ .field.floating[data-has-value="true"] label,
117
+ :host(:focus-within) .field.floating label {
118
+ top: 0.35rem;
119
+ transform: translateY(0) scale(0.85);
120
+ color: var(--ui-input-label-color, #475569);
121
+ }
122
+
83
123
  input {
84
124
  box-sizing: border-box;
85
125
  width: 100%;
@@ -105,34 +145,47 @@ t.styles = d`
105
145
  opacity: 0.6;
106
146
  cursor: not-allowed;
107
147
  }
148
+
149
+ .field.floating input {
150
+ padding-top: var(--ui-input-floating-padding-top, 0.95rem);
151
+ padding-right: var(--ui-input-floating-padding-right, 0.75rem);
152
+ padding-bottom: var(--ui-input-floating-padding-bottom, 0.45rem);
153
+ padding-left: var(--ui-input-floating-padding-left, 0.75rem);
154
+ }
108
155
  `;
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([
156
+ a([
157
+ l({ type: String })
158
+ ], e.prototype, "value", 2);
159
+ a([
160
+ l({ type: String })
161
+ ], e.prototype, "placeholder", 2);
162
+ a([
163
+ l({ type: String, reflect: !0 })
164
+ ], e.prototype, "name", 2);
165
+ a([
166
+ l({ type: Boolean, reflect: !0 })
167
+ ], e.prototype, "disabled", 2);
168
+ a([
169
+ l({ type: Boolean, reflect: !0 })
170
+ ], e.prototype, "required", 2);
171
+ a([
172
+ l({ type: String, reflect: !0 })
173
+ ], e.prototype, "type", 2);
174
+ a([
175
+ l({ type: String, reflect: !0 })
176
+ ], e.prototype, "autocomplete", 2);
177
+ a([
178
+ l({ type: String })
179
+ ], e.prototype, "label", 2);
180
+ a([
181
+ l({ type: String, attribute: "label-position" })
182
+ ], e.prototype, "labelPosition", 2);
183
+ a([
131
184
  f("input")
132
- ], t.prototype, "inputEl", 2);
133
- t = i([
185
+ ], e.prototype, "inputEl", 2);
186
+ e = a([
134
187
  b("dui-input")
135
- ], t);
188
+ ], e);
136
189
  export {
137
- t as DuiInput
190
+ e as DuiInput
138
191
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grayscale-dev/dragon",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Framework-agnostic Web Components built with Lit.",
5
5
  "type": "module",
6
6
  "files": [