@transcodes/ui-components 0.3.0 → 0.3.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +124 -79
  3. package/dist/controllers/animation.controller.js +32 -0
  4. package/dist/controllers/base.controller.js +8 -0
  5. package/dist/controllers/form-validation.controller.js +49 -0
  6. package/dist/controllers/history.controller.js +26 -0
  7. package/dist/controllers/loading.controller.js +27 -0
  8. package/dist/controllers/match-media.controller.js +20 -0
  9. package/dist/controllers/message-bus.controller.js +45 -0
  10. package/dist/controllers/storage.controller.js +40 -0
  11. package/dist/index.js +80 -0
  12. package/dist/primitives/tc-box.js +38 -0
  13. package/dist/primitives/tc-button.js +167 -0
  14. package/dist/primitives/tc-callout.js +86 -0
  15. package/dist/primitives/tc-card.js +76 -0
  16. package/dist/primitives/tc-chip.js +79 -0
  17. package/dist/primitives/tc-container.js +62 -0
  18. package/dist/primitives/tc-divider.js +76 -0
  19. package/dist/primitives/tc-error-message.js +74 -0
  20. package/dist/primitives/tc-form-header.js +120 -0
  21. package/dist/primitives/tc-icon.js +95 -0
  22. package/dist/primitives/tc-input-with-chip.js +242 -0
  23. package/dist/primitives/tc-input.js +262 -0
  24. package/dist/primitives/tc-item-button.js +168 -0
  25. package/dist/primitives/tc-item.js +93 -0
  26. package/dist/primitives/tc-otp-input.js +230 -0
  27. package/dist/primitives/tc-section.js +48 -0
  28. package/dist/primitives/tc-spinner.js +87 -0
  29. package/dist/primitives/tc-symbol.js +56 -0
  30. package/dist/primitives/tc-text.js +145 -0
  31. package/dist/primitives/tc-toast.js +189 -0
  32. package/dist/screens/tc-error-screen.js +119 -0
  33. package/dist/screens/tc-loading-screen.js +77 -0
  34. package/dist/screens/tc-success-screen.js +192 -0
  35. package/dist/styles/shared.js +7 -0
  36. package/dist/widgets/tc-authenticator-card.js +213 -0
  37. package/dist/widgets/tc-floating-button.js +132 -0
  38. package/dist/widgets/tc-iframe-modal.js +263 -0
  39. package/dist/widgets/tc-installation-banner.js +234 -0
  40. package/dist/widgets/tc-ios-installation-guide.js +240 -0
  41. package/dist/widgets/tc-notification-modal.js +230 -0
  42. package/dist/widgets/tc-offline-modal.js +202 -0
  43. package/dist/widgets/tc-page-decoration.js +126 -0
  44. package/package.json +25 -7
  45. package/dist/ui-components.css +0 -1
  46. package/dist/ui-components.js +0 -4981
@@ -0,0 +1,262 @@
1
+ import { LitElement as c, html as d, css as m } from "lit";
2
+ import { property as i, state as h, customElement as b } from "lit/decorators.js";
3
+ import { classMap as u } from "lit/directives/class-map.js";
4
+ import { styleMap as y } from "lit/directives/style-map.js";
5
+ import { sharedStyles as v } from "../styles/shared.js";
6
+ var f = Object.defineProperty, g = Object.getOwnPropertyDescriptor, r = (e, o, n, a) => {
7
+ for (var s = a > 1 ? void 0 : a ? g(o, n) : o, l = e.length - 1, p; l >= 0; l--)
8
+ (p = e[l]) && (s = (a ? p(o, n, s) : p(s)) || s);
9
+ return a && s && f(o, n, s), s;
10
+ };
11
+ let t = class extends c {
12
+ constructor() {
13
+ super(...arguments), this.label = "", this.type = "text", this.placeholder = "", this.value = "", this.error = "", this.disabled = !1, this.required = !1, this.name = "", this.autocomplete = "", this.inputmode = "", this.maxlength = 0, this.sx = {}, this.inputId = `tc-input-${Math.random().toString(36).slice(2)}`, this.isFocused = !1;
14
+ }
15
+ render() {
16
+ const e = this.error.length > 0, o = {
17
+ "field-group": !0,
18
+ focused: this.isFocused,
19
+ "has-error": e
20
+ }, n = {
21
+ "input-wrapper": !0,
22
+ focused: this.isFocused,
23
+ "has-error": e
24
+ }, a = {
25
+ input: !0,
26
+ "has-error": e
27
+ };
28
+ return d`
29
+ <div class=${u(o)}>
30
+ ${this.label ? d`<label part="label" class="field-label" for=${this.inputId}>${this.label}</label>` : ""}
31
+ <div part="wrapper" class=${u(n)}>
32
+ <input
33
+ part="input"
34
+ id=${this.inputId}
35
+ class=${u(a)}
36
+ type=${this.type}
37
+ name=${this.name}
38
+ placeholder=${this.placeholder}
39
+ .value=${this.value}
40
+ ?disabled=${this.disabled}
41
+ ?required=${this.required}
42
+ autocomplete=${this.autocomplete || "off"}
43
+ inputmode=${this.inputmode || ""}
44
+ maxlength=${this.maxlength || ""}
45
+ aria-invalid=${e ? "true" : "false"}
46
+ aria-describedby=${e ? `${this.inputId}-error` : ""}
47
+ style=${y(this.sx)}
48
+ @input=${this.handleInput}
49
+ @focus=${this.handleFocus}
50
+ @blur=${this.handleBlur}
51
+ @keydown=${this.handleKeydown}
52
+ @paste=${this.handlePaste}
53
+ />
54
+ <div part="ink-line" class="ink-line"></div>
55
+ </div>
56
+ ${e ? d`<p part="error" id="${this.inputId}-error" class="input-error-text" role="alert">
57
+ ${this.error}
58
+ </p>` : ""}
59
+ </div>
60
+ `;
61
+ }
62
+ handleInput(e) {
63
+ const o = e.target;
64
+ this.value = o.value, this.dispatchEvent(
65
+ new CustomEvent("tc-input", {
66
+ bubbles: !0,
67
+ composed: !0,
68
+ detail: { value: o.value }
69
+ })
70
+ );
71
+ }
72
+ handleFocus() {
73
+ this.isFocused = !0;
74
+ }
75
+ handleBlur(e) {
76
+ const o = e.target;
77
+ this.isFocused = !1, this.dispatchEvent(
78
+ new CustomEvent("tc-blur", {
79
+ bubbles: !0,
80
+ composed: !0,
81
+ detail: { value: o.value }
82
+ })
83
+ );
84
+ }
85
+ handleKeydown(e) {
86
+ this.dispatchEvent(
87
+ new CustomEvent("tc-keydown", {
88
+ bubbles: !0,
89
+ composed: !0,
90
+ detail: { key: e.key, value: this.value, originalEvent: e }
91
+ })
92
+ );
93
+ }
94
+ handlePaste(e) {
95
+ this.dispatchEvent(
96
+ new CustomEvent("tc-paste", {
97
+ bubbles: !0,
98
+ composed: !0,
99
+ detail: { data: e.clipboardData?.getData("text"), originalEvent: e }
100
+ })
101
+ );
102
+ }
103
+ focus() {
104
+ this.shadowRoot?.querySelector("input")?.focus();
105
+ }
106
+ };
107
+ t.styles = [
108
+ v,
109
+ m`
110
+ :host {
111
+ display: block;
112
+ }
113
+
114
+ /* Extend design-tokens .field-group */
115
+ .field-group {
116
+ width: 100%;
117
+ }
118
+
119
+ /* Label color change on focus - extends design-tokens .field-label */
120
+ .field-group.focused .field-label {
121
+ color: var(--accent-primary);
122
+ }
123
+
124
+ .field-group.has-error .field-label {
125
+ color: var(--error-base);
126
+ }
127
+
128
+ .input-wrapper {
129
+ position: relative;
130
+ width: 100%;
131
+ }
132
+
133
+ /* Extend design-tokens .input */
134
+ .input {
135
+ width: 100%;
136
+ box-sizing: border-box;
137
+ }
138
+
139
+ .input:disabled {
140
+ opacity: var(--opacity-disabled);
141
+ cursor: not-allowed;
142
+ }
143
+
144
+ /* Ink line animation */
145
+ .ink-line {
146
+ position: absolute;
147
+ bottom: 0;
148
+ left: 50%;
149
+ transform: translateX(-50%);
150
+ width: 0;
151
+ height: 0.125rem;
152
+ background: linear-gradient(
153
+ 90deg,
154
+ var(--accent-primary) 0%,
155
+ var(--accent-primary-hover) 100%
156
+ );
157
+ border-radius: 0.0625rem;
158
+ transition: width 300ms cubic-bezier(0.4, 0, 0.2, 1);
159
+ pointer-events: none;
160
+ }
161
+
162
+ .input-wrapper.focused .ink-line {
163
+ width: 60%;
164
+ }
165
+
166
+ /* Error states */
167
+ .input.has-error {
168
+ border-color: var(--error-base);
169
+ background: var(--error-bg);
170
+ }
171
+
172
+ .input.has-error:focus {
173
+ border-color: var(--error-base);
174
+ box-shadow: 0 0 0 0.1875rem var(--error-border);
175
+ }
176
+
177
+ .input-wrapper.has-error .ink-line {
178
+ background: linear-gradient(
179
+ 90deg,
180
+ var(--error-base) 0%,
181
+ var(--error-base) 100%
182
+ );
183
+ }
184
+
185
+ .input-error-text {
186
+ font-size: var(--font-size-sm);
187
+ color: var(--error-base);
188
+ margin: 0;
189
+ animation: slideDown 300ms ease backwards;
190
+ }
191
+
192
+ @keyframes slideDown {
193
+ from {
194
+ opacity: 0;
195
+ transform: translateY(-0.25rem);
196
+ }
197
+ to {
198
+ opacity: 1;
199
+ transform: translateY(0);
200
+ }
201
+ }
202
+
203
+ /* Reduced motion */
204
+ @media (prefers-reduced-motion: reduce) {
205
+ .field-label,
206
+ .input,
207
+ .ink-line,
208
+ .input-error-text {
209
+ transition-duration: 0.01ms !important;
210
+ animation-duration: 0.01ms !important;
211
+ }
212
+ }
213
+ `
214
+ ];
215
+ r([
216
+ i({ type: String })
217
+ ], t.prototype, "label", 2);
218
+ r([
219
+ i({ type: String })
220
+ ], t.prototype, "type", 2);
221
+ r([
222
+ i({ type: String })
223
+ ], t.prototype, "placeholder", 2);
224
+ r([
225
+ i({ type: String })
226
+ ], t.prototype, "value", 2);
227
+ r([
228
+ i({ type: String })
229
+ ], t.prototype, "error", 2);
230
+ r([
231
+ i({ type: Boolean })
232
+ ], t.prototype, "disabled", 2);
233
+ r([
234
+ i({ type: Boolean })
235
+ ], t.prototype, "required", 2);
236
+ r([
237
+ i({ type: String })
238
+ ], t.prototype, "name", 2);
239
+ r([
240
+ i({ type: String })
241
+ ], t.prototype, "autocomplete", 2);
242
+ r([
243
+ i({ type: String })
244
+ ], t.prototype, "inputmode", 2);
245
+ r([
246
+ i({ type: Number })
247
+ ], t.prototype, "maxlength", 2);
248
+ r([
249
+ i({ type: Object })
250
+ ], t.prototype, "sx", 2);
251
+ r([
252
+ h()
253
+ ], t.prototype, "inputId", 2);
254
+ r([
255
+ h()
256
+ ], t.prototype, "isFocused", 2);
257
+ t = r([
258
+ b("tc-input")
259
+ ], t);
260
+ export {
261
+ t as TcInput
262
+ };
@@ -0,0 +1,168 @@
1
+ import { LitElement as c, html as d, css as f } from "lit";
2
+ import { property as o, customElement as u } from "lit/decorators.js";
3
+ import { styleMap as h } from "lit/directives/style-map.js";
4
+ var m = Object.defineProperty, b = Object.getOwnPropertyDescriptor, r = (i, s, a, n) => {
5
+ for (var e = n > 1 ? void 0 : n ? b(s, a) : s, l = i.length - 1, p; l >= 0; l--)
6
+ (p = i[l]) && (e = (n ? p(s, a, e) : p(e)) || e);
7
+ return n && e && m(s, a, e), e;
8
+ };
9
+ let t = class extends c {
10
+ constructor() {
11
+ super(...arguments), this.gap = "var(--space-md)", this.padding = "var(--space-md)", this.disabled = !1, this.showArrow = !0, this.sx = {};
12
+ }
13
+ handleClick() {
14
+ this.disabled || this.dispatchEvent(
15
+ new CustomEvent("tc-click", {
16
+ bubbles: !0,
17
+ composed: !0
18
+ })
19
+ );
20
+ }
21
+ render() {
22
+ const i = {
23
+ "--item-padding": this.padding,
24
+ "--item-gap": this.gap,
25
+ ...this.sx
26
+ };
27
+ return d`
28
+ <button
29
+ part="button"
30
+ class="button"
31
+ ?disabled=${this.disabled}
32
+ style=${h(i)}
33
+ @click=${this.handleClick}
34
+ >
35
+ <div part="prefix" class="prefix">
36
+ <slot name="prefix"></slot>
37
+ </div>
38
+ <div part="content" class="content">
39
+ <slot></slot>
40
+ </div>
41
+ <div part="suffix" class="suffix">
42
+ <slot name="suffix"></slot>
43
+ </div>
44
+ ${this.showArrow ? d`
45
+ <svg
46
+ part="arrow"
47
+ class="arrow"
48
+ viewBox="0 0 24 24"
49
+ fill="none"
50
+ stroke="currentColor"
51
+ stroke-width="2"
52
+ stroke-linecap="round"
53
+ stroke-linejoin="round"
54
+ >
55
+ <polyline points="9 18 15 12 9 6"></polyline>
56
+ </svg>
57
+ ` : ""}
58
+ </button>
59
+ `;
60
+ }
61
+ };
62
+ t.styles = f`
63
+ :host {
64
+ display: block;
65
+ width: 100%;
66
+ }
67
+
68
+ .button {
69
+ display: flex;
70
+ align-items: center;
71
+ width: 100%;
72
+ padding: var(--item-padding);
73
+ gap: var(--item-gap);
74
+ background: var(--paper-cream);
75
+ border: none;
76
+ border-radius: var(--radius-md);
77
+ box-sizing: border-box;
78
+ cursor: pointer;
79
+ font-family: inherit;
80
+ text-align: left;
81
+ transition: var(--transition-fast);
82
+ }
83
+
84
+ .button:hover:not(:disabled) {
85
+ background: var(--paper-warm);
86
+ }
87
+
88
+ .button:active:not(:disabled) {
89
+ transform: scale(0.995);
90
+ }
91
+
92
+ .button:focus-visible {
93
+ outline: 2px solid var(--accent-primary);
94
+ outline-offset: 2px;
95
+ }
96
+
97
+ .button:disabled {
98
+ opacity: 0.6;
99
+ cursor: not-allowed;
100
+ }
101
+
102
+ .prefix {
103
+ flex-shrink: 0;
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: center;
107
+ }
108
+
109
+ .content {
110
+ flex: 1;
111
+ min-width: 0;
112
+ font-family: var(--font-body);
113
+ font-size: var(--font-size-base);
114
+ color: var(--ink-dark);
115
+ }
116
+
117
+ .suffix {
118
+ flex-shrink: 0;
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ }
123
+
124
+ .arrow {
125
+ flex-shrink: 0;
126
+ width: 1.25rem;
127
+ height: 1.25rem;
128
+ color: var(--ink-light);
129
+ transition: var(--transition-fast);
130
+ }
131
+
132
+ .button:hover:not(:disabled) .arrow {
133
+ color: var(--ink-medium);
134
+ transform: translateX(2px);
135
+ }
136
+
137
+ /* Hide empty slots */
138
+ .prefix:not(:has(*)),
139
+ .suffix:not(:has(*)) {
140
+ display: none;
141
+ }
142
+
143
+ /* Hide arrow when suffix has content */
144
+ .suffix:has(*) + .arrow {
145
+ display: none;
146
+ }
147
+ `;
148
+ r([
149
+ o({ type: String })
150
+ ], t.prototype, "gap", 2);
151
+ r([
152
+ o({ type: String })
153
+ ], t.prototype, "padding", 2);
154
+ r([
155
+ o({ type: Boolean })
156
+ ], t.prototype, "disabled", 2);
157
+ r([
158
+ o({ type: Boolean, attribute: "show-arrow" })
159
+ ], t.prototype, "showArrow", 2);
160
+ r([
161
+ o({ type: Object })
162
+ ], t.prototype, "sx", 2);
163
+ t = r([
164
+ u("tc-item-button")
165
+ ], t);
166
+ export {
167
+ t as TcItemButton
168
+ };
@@ -0,0 +1,93 @@
1
+ import { LitElement as d, html as f, css as m } from "lit";
2
+ import { property as l, customElement as c } from "lit/decorators.js";
3
+ import { styleMap as v } from "lit/directives/style-map.js";
4
+ var x = Object.defineProperty, y = Object.getOwnPropertyDescriptor, a = (i, s, p, r) => {
5
+ for (var t = r > 1 ? void 0 : r ? y(s, p) : s, n = i.length - 1, o; n >= 0; n--)
6
+ (o = i[n]) && (t = (r ? o(s, p, t) : o(t)) || t);
7
+ return r && t && x(s, p, t), t;
8
+ };
9
+ let e = class extends d {
10
+ constructor() {
11
+ super(...arguments), this.gap = "var(--space-md)", this.padding = "var(--space-md)", this.sx = {};
12
+ }
13
+ render() {
14
+ const i = {
15
+ "--item-padding": this.padding,
16
+ "--item-gap": this.gap,
17
+ ...this.sx
18
+ };
19
+ return f`
20
+ <div part="item" class="item" style=${v(i)}>
21
+ <div part="prefix" class="prefix">
22
+ <slot name="prefix"></slot>
23
+ </div>
24
+ <div part="content" class="content">
25
+ <slot></slot>
26
+ </div>
27
+ <div part="suffix" class="suffix">
28
+ <slot name="suffix"></slot>
29
+ </div>
30
+ </div>
31
+ `;
32
+ }
33
+ };
34
+ e.styles = m`
35
+ :host {
36
+ display: block;
37
+ width: 100%;
38
+ }
39
+
40
+ .item {
41
+ display: flex;
42
+ align-items: center;
43
+ width: 100%;
44
+ padding: var(--item-padding);
45
+ gap: var(--item-gap);
46
+ background: var(--paper-cream);
47
+ border-radius: var(--radius-md);
48
+ box-sizing: border-box;
49
+ }
50
+
51
+ .prefix {
52
+ flex-shrink: 0;
53
+ display: flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ }
57
+
58
+ .content {
59
+ flex: 1;
60
+ min-width: 0;
61
+ font-family: var(--font-body);
62
+ font-size: var(--font-size-base);
63
+ color: var(--ink-dark);
64
+ }
65
+
66
+ .suffix {
67
+ flex-shrink: 0;
68
+ display: flex;
69
+ align-items: center;
70
+ justify-content: center;
71
+ }
72
+
73
+ /* Hide empty slots */
74
+ .prefix:not(:has(*)),
75
+ .suffix:not(:has(*)) {
76
+ display: none;
77
+ }
78
+ `;
79
+ a([
80
+ l({ type: String })
81
+ ], e.prototype, "gap", 2);
82
+ a([
83
+ l({ type: String })
84
+ ], e.prototype, "padding", 2);
85
+ a([
86
+ l({ type: Object })
87
+ ], e.prototype, "sx", 2);
88
+ e = a([
89
+ c("tc-item")
90
+ ], e);
91
+ export {
92
+ e as TcItem
93
+ };