revotech-ui-kit 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. package/.editorconfig +29 -0
  2. package/.eslintrc +10 -0
  3. package/.storybook/main.ts +17 -0
  4. package/.storybook/preview-head.html +1 -0
  5. package/.storybook/preview.ts +17 -0
  6. package/LICENSE +21 -0
  7. package/README.md +30 -0
  8. package/assets/fonts/Geist/Geist-Black.otf +0 -0
  9. package/assets/fonts/Geist/Geist-Black.woff2 +0 -0
  10. package/assets/fonts/Geist/Geist-Bold.otf +0 -0
  11. package/assets/fonts/Geist/Geist-Bold.woff2 +0 -0
  12. package/assets/fonts/Geist/Geist-Light.otf +0 -0
  13. package/assets/fonts/Geist/Geist-Light.woff2 +0 -0
  14. package/assets/fonts/Geist/Geist-Medium.otf +0 -0
  15. package/assets/fonts/Geist/Geist-Medium.woff2 +0 -0
  16. package/assets/fonts/Geist/Geist-Regular.otf +0 -0
  17. package/assets/fonts/Geist/Geist-Regular.woff2 +0 -0
  18. package/assets/fonts/Geist/Geist-SemiBold.otf +0 -0
  19. package/assets/fonts/Geist/Geist-SemiBold.woff2 +0 -0
  20. package/assets/fonts/Geist/Geist-Thin.otf +0 -0
  21. package/assets/fonts/Geist/Geist-Thin.woff2 +0 -0
  22. package/assets/fonts/Geist/Geist-UltraBlack.otf +0 -0
  23. package/assets/fonts/Geist/Geist-UltraBlack.woff2 +0 -0
  24. package/assets/fonts/Geist/Geist-UltraLight.otf +0 -0
  25. package/assets/fonts/Geist/Geist-UltraLight.woff2 +0 -0
  26. package/assets/fonts/Geist/GeistVariableVF.ttf +0 -0
  27. package/assets/fonts/Geist/GeistVariableVF.woff2 +0 -0
  28. package/assets/fonts/Geist/LICENSE.TXT +92 -0
  29. package/assets/open-wc-logo.svg +29 -0
  30. package/index.html +362 -0
  31. package/package.json +117 -0
  32. package/rollup.config.js +71 -0
  33. package/src/components/atoms/button/button.atom.ts +39 -0
  34. package/src/components/atoms/button/button.stories.ts +186 -0
  35. package/src/components/atoms/button/button.style.ts +31 -0
  36. package/src/components/atoms/button/button.type.ts +10 -0
  37. package/src/components/atoms/checkbox/checkbox.atom.ts +62 -0
  38. package/src/components/atoms/checkbox/checkbox.stories.ts +42 -0
  39. package/src/components/atoms/command-empty/command-empty.atom.ts +44 -0
  40. package/src/components/atoms/command-group/command-group.atom.ts +60 -0
  41. package/src/components/atoms/command-item/command-item.atom.ts +74 -0
  42. package/src/components/atoms/command-list/command-list.atom.ts +37 -0
  43. package/src/components/atoms/command-separator/command-separator.atom.ts +42 -0
  44. package/src/components/atoms/dialog/dialog.atom.ts +301 -0
  45. package/src/components/atoms/dialog/dialog.stories.ts +86 -0
  46. package/src/components/atoms/index.ts +10 -0
  47. package/src/components/atoms/input/input.atom.ts +34 -0
  48. package/src/components/atoms/input/input.stories.ts +89 -0
  49. package/src/components/atoms/input/input.type.ts +24 -0
  50. package/src/components/atoms/label/label.atom.ts +40 -0
  51. package/src/components/atoms/label/label.stories.ts +18 -0
  52. package/src/components/atoms/label/label.style.ts +5 -0
  53. package/src/components/command/command.stories.ts +154 -0
  54. package/src/components/command/command.ts +391 -0
  55. package/src/components/index.ts +2 -0
  56. package/src/components/molecules/command/command.molecules.ts +31 -0
  57. package/src/components/molecules/command-input/command-input.atom.ts +130 -0
  58. package/src/components/molecules/index.ts +1 -0
  59. package/src/components/popover.ts +247 -0
  60. package/src/globals.css +1806 -0
  61. package/src/helpers/index.ts +2 -0
  62. package/src/helpers/mouse-conroller.helper.ts +42 -0
  63. package/src/helpers/style.helpers.ts +6 -0
  64. package/src/interfaces/actionable.interface.ts +6 -0
  65. package/src/interfaces/atomic.interface.ts +6 -0
  66. package/src/interfaces/changeable.interface.ts +14 -0
  67. package/src/interfaces/child-support-atomic.interface.ts +5 -0
  68. package/src/interfaces/index.ts +6 -0
  69. package/src/interfaces/intractable.interface.ts +6 -0
  70. package/src/interfaces/variant.interface.ts +3 -0
  71. package/src/lib/index.ts +0 -0
  72. package/src/lib/next/next.lib.ts +0 -0
  73. package/src/lib/react/react.lib.ts +0 -0
  74. package/src/styles/index.ts +1 -0
  75. package/src/styles/tw.styles.ts +1867 -0
  76. package/src/tailwind-lib.css +95 -0
  77. package/src/wc-ui-app.ts +81 -0
  78. package/tailwind.config.js +81 -0
  79. package/test/wc-ui-app.test.ts +22 -0
  80. package/tsconfig.json +25 -0
  81. package/web-dev-server.config.mjs +26 -0
  82. package/web-test-runner.config.mjs +41 -0
@@ -0,0 +1,301 @@
1
+ /* eslint-disable no-use-before-define */
2
+ import {
3
+ LitElement,
4
+ html,
5
+ css,
6
+ PropertyValueMap,
7
+ nothing,
8
+ PropertyValues,
9
+ } from 'lit';
10
+ import { customElement, property } from 'lit/decorators.js';
11
+ import { cn } from '@/helpers';
12
+ import { TWStyles } from '@/styles';
13
+
14
+ const STATE_OPEN = 'open';
15
+ const STATE_CLOSED = 'closed';
16
+
17
+ @customElement('rtg-dialog')
18
+ export class Dialog extends LitElement {
19
+ static styles = [css``, TWStyles];
20
+
21
+ @property({ attribute: 'data-state', type: String }) state = STATE_CLOSED;
22
+
23
+ private get _content(): DialogContent | null {
24
+ const slot = this.shadowRoot?.querySelector('slot');
25
+ const children = slot?.assignedElements();
26
+ if (children) {
27
+ for (let index = 0; index < children.length; index++) {
28
+ if (children[index] instanceof DialogContent) {
29
+ return children[index] as DialogContent;
30
+ }
31
+ }
32
+ }
33
+
34
+ return null;
35
+ }
36
+
37
+ protected updated(_changedProperties: PropertyValues): void {
38
+ super.updated(_changedProperties);
39
+ const content = this._content;
40
+ if (content) {
41
+ content.dataset.state = this.state;
42
+ }
43
+ }
44
+
45
+ render() {
46
+ return html`
47
+ <div rtgdlg-root>
48
+ ${this.state === STATE_OPEN
49
+ ? html` <rtg-dialog-overlay></rtg-dialog-overlay>`
50
+ : nothing}
51
+ <slot></slot>
52
+ </div>
53
+ `;
54
+ }
55
+ }
56
+
57
+ @customElement('rtg-dialog-content')
58
+ export class DialogContent extends LitElement {
59
+ static styles = [css``, TWStyles];
60
+
61
+ @property({ attribute: 'data-state', type: String }) state = STATE_CLOSED;
62
+
63
+ private get _dialog(): Dialog | null {
64
+ let parent = this.parentElement;
65
+
66
+ while (parent) {
67
+ if (parent instanceof Dialog) {
68
+ return parent;
69
+ }
70
+ parent = parent.parentElement;
71
+ }
72
+ return parent;
73
+ }
74
+
75
+ private handleCloseButtonClick = () => {
76
+ const dialog = this._dialog;
77
+ if (dialog) {
78
+ dialog.dataset.state = STATE_CLOSED;
79
+ }
80
+ };
81
+
82
+ render() {
83
+ return html`${this.state === STATE_OPEN
84
+ ? html`
85
+ <div
86
+ class="${cn(
87
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
88
+ this.className
89
+ )}"
90
+ rtgdlg-content
91
+ >
92
+ <slot></slot>
93
+ <button
94
+ type="button"
95
+ @click="${this.handleCloseButtonClick}"
96
+ class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
97
+ >
98
+ <svg
99
+ xmlns="http://www.w3.org/2000/svg"
100
+ width="24"
101
+ height="24"
102
+ viewBox="0 0 24 24"
103
+ fill="none"
104
+ stroke="currentColor"
105
+ stroke-width="2"
106
+ stroke-linecap="round"
107
+ stroke-linejoin="round"
108
+ class="h-4 w-4"
109
+ >
110
+ <path d="M18 6 6 18"></path>
111
+ <path d="m6 6 12 12"></path></svg
112
+ ><span class="sr-only">Close</span>
113
+ </button>
114
+ </div>
115
+ `
116
+ : nothing}`;
117
+ }
118
+ }
119
+
120
+ @customElement('rtg-dialog-overlay')
121
+ export class DialogOverlay extends LitElement {
122
+ static styles = [css``, TWStyles];
123
+
124
+ render() {
125
+ return html`
126
+ <div
127
+ class="${cn(
128
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
129
+ this.className
130
+ )}"
131
+ ></div>
132
+ `;
133
+ }
134
+ }
135
+
136
+ @customElement('rtg-dialog-header')
137
+ export class DialogHeader extends LitElement {
138
+ static styles = [css``, TWStyles];
139
+
140
+ @property({ attribute: 'title', type: String }) _title = '';
141
+
142
+ @property({ type: String }) description = '';
143
+
144
+ render() {
145
+ return html`
146
+ <div
147
+ class="${cn(
148
+ 'flex flex-col space-y-1.5 text-center sm:text-left',
149
+ this.className
150
+ )}"
151
+ >
152
+ <h2
153
+ class="${cn(
154
+ 'text-lg font-semibold leading-none tracking-tight',
155
+ this.className
156
+ )}"
157
+ >
158
+ ${this._title}
159
+ </h2>
160
+ <p class="${cn('text-sm text-muted-foreground', this.className)}">
161
+ ${this.description}
162
+ </p>
163
+ </div>
164
+ `;
165
+ }
166
+ }
167
+
168
+ @customElement('rtg-dialog-footer')
169
+ export class DialogFooter extends LitElement {
170
+ static styles = [css``, TWStyles];
171
+
172
+ render() {
173
+ return html`
174
+ <div
175
+ class="${cn(
176
+ 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
177
+ this.className
178
+ )}"
179
+ >
180
+ <slot></slot>
181
+ </div>
182
+ `;
183
+ }
184
+ }
185
+
186
+ // @customElement('rtg-dialog-title')
187
+ // export class DialogTitle extends LitElement {
188
+ // static styles = [css``, TWStyles];
189
+
190
+ // render() {
191
+ // return html`
192
+ // <h2
193
+ // class="${cn(
194
+ // 'text-lg font-semibold leading-none tracking-tight',
195
+ // this.className
196
+ // )}"
197
+ // >
198
+ // <slot></slot>
199
+ // </h2>
200
+ // `;
201
+ // }
202
+ // }
203
+
204
+ // @customElement('rtg-dialog-description')
205
+ // export class DialogDescription extends LitElement {
206
+ // static styles = [css``, TWStyles];
207
+
208
+ // render() {
209
+ // return html`
210
+ // <p class="${cn('text-sm text-muted-foreground', this.className)}">
211
+ // <slot></slot>
212
+ // </p>
213
+ // `;
214
+ // }
215
+ // }
216
+
217
+ @customElement('rtg-dialog-trigger')
218
+ export class DialogTrigger extends LitElement {
219
+ static styles = [css``, TWStyles];
220
+
221
+ private get _dialog(): Dialog | null {
222
+ let parent = this.parentElement;
223
+
224
+ while (parent) {
225
+ if (parent instanceof Dialog) {
226
+ return parent;
227
+ }
228
+ parent = parent.parentElement;
229
+ }
230
+ return parent;
231
+ }
232
+
233
+ protected firstUpdated(
234
+ _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
235
+ ): void {
236
+ super.firstUpdated(_changedProperties);
237
+ const slot = this.shadowRoot?.querySelector('slot');
238
+ const children = slot?.assignedElements();
239
+ if (children && children.length > 0) {
240
+ const button = children[0];
241
+
242
+ button.addEventListener('click', () => {
243
+ const dialog = this._dialog;
244
+ if (dialog) {
245
+ dialog.dataset.state = STATE_OPEN;
246
+ }
247
+ });
248
+ }
249
+ }
250
+
251
+ render() {
252
+ return html`
253
+ <div>
254
+ <slot></slot>
255
+ </div>
256
+ `;
257
+ }
258
+ }
259
+
260
+ @customElement('rtg-dialog-close')
261
+ export class DialogClose extends LitElement {
262
+ static styles = [css``, TWStyles];
263
+
264
+ private get _dialog(): Dialog | null {
265
+ let parent = this.parentElement;
266
+
267
+ while (parent) {
268
+ if (parent instanceof Dialog) {
269
+ return parent;
270
+ }
271
+ parent = parent.parentElement;
272
+ }
273
+ return parent;
274
+ }
275
+
276
+ protected firstUpdated(
277
+ _changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>
278
+ ): void {
279
+ super.firstUpdated(_changedProperties);
280
+ const slot = this.shadowRoot?.querySelector('slot');
281
+ const children = slot?.assignedElements();
282
+ if (children && children.length > 0) {
283
+ const button = children[0];
284
+
285
+ button.addEventListener('click', () => {
286
+ const dialog = this._dialog;
287
+ if (dialog) {
288
+ dialog.dataset.state = STATE_CLOSED;
289
+ }
290
+ });
291
+ }
292
+ }
293
+
294
+ render() {
295
+ return html`
296
+ <div>
297
+ <slot></slot>
298
+ </div>
299
+ `;
300
+ }
301
+ }
@@ -0,0 +1,86 @@
1
+ import { html } from 'lit';
2
+ import { Meta, StoryObj } from '@storybook/web-components';
3
+ import '../input/input.atom';
4
+ import './dialog.atom';
5
+
6
+ const meta: Meta = {
7
+ component: 'components/dialog',
8
+ };
9
+
10
+ export default meta;
11
+ type Story = StoryObj;
12
+
13
+ export const ConfirmationDialog: Story = {
14
+ render: () =>
15
+ html`<div class="flex flex-nowrap">
16
+ <div class="flex flex-wrap space-x-4 gap-5 mx-3">
17
+ <rtg-dialog>
18
+ <rtg-dialog-trigger>
19
+ <rtg-button>Open Dialog</rtg-button>
20
+ </rtg-dialog-trigger>
21
+ <rtg-dialog-content>
22
+ <rtg-dialog-header title="Are you absolutely sure?" description="This action cannot be undone. This will permanently delete your
23
+ content.">
24
+ <rtg-dialog-title>Are you absolutely sure?</rtg-dialog-title>
25
+ <rtg-dialog-description>
26
+ This action cannot be undone. This will permanently delete your
27
+ content.</rtg-dialog-description
28
+ >
29
+ </rtg-dialog-header>
30
+ <rtg-dialog-footer>
31
+ <div class="flex w-full justify-between space-x-1">
32
+ <rtg-dialog-close><rtg-button variant="secondary">Close</rtg-button></rtg-dialog-close>
33
+ <div class="justify-end">
34
+ <rtg-button variant="destructive">Delete</rtg-button>
35
+ <rtg-button>Cancel</rtg-button>
36
+ </div>
37
+ </div>
38
+ </rtg-dialog-content>
39
+ </rtg-dialog>
40
+ </div>
41
+ </div>`,
42
+ };
43
+
44
+ export const ModalForm: Story = {
45
+ render: () => html`
46
+ <rtg-dialog>
47
+ <rtg-dialog-trigger>
48
+ <rtg-button variant="outline">Edit Profile</rtg-button>
49
+ </rtg-dialog-trigger>
50
+ <rtg-dialog-content class="sm:max-w-[425px]">
51
+ <rtg-dialog-header title="Edit Profile" description="Make changes to your profile here. Click save when you're done.">
52
+ <!-- <rtg-dialog-title>Edit Profile</rtg-dialog-title>
53
+ <rtg-dialog-description>
54
+ Make changes to your profile here. Click save when you're done.</rtg-dialog-description
55
+ > -->
56
+ </rtg-dialog-header>
57
+ <div class="grid gap-4 py-4">
58
+ <div class="grid grid-cols-4 items-center gap-4">
59
+ <rtg-label for="name" class="text-right">
60
+ Name
61
+ </rtg-label>
62
+ <rtg-input
63
+ id="name"
64
+ defaultValue="Pedro Duarte"
65
+ class="col-span-3"
66
+ >
67
+ </rtg-input>
68
+ </div>
69
+ <div class="grid grid-cols-4 items-center gap-4">
70
+ <rtg-label for="username" class="text-right">
71
+ Username
72
+ </rtg-label>
73
+ <rtg-input
74
+ id="username"
75
+ defaultValue="@peduarte"
76
+ class="col-span-3"
77
+ >
78
+ </rtg-input>
79
+ </div>
80
+ </div>
81
+ <rtg-dialog-footer>
82
+ <rtg-button type="submit" class="w-full sm:w-min">Save changes</rtg-button>
83
+ </rtg-dialog-content>
84
+ </rtg-dialog>
85
+ `,
86
+ };
@@ -0,0 +1,10 @@
1
+ export * from './button/button.atom';
2
+ export * from './checkbox/checkbox.atom';
3
+ export * from './dialog/dialog.atom';
4
+ export * from './input/input.atom';
5
+ export * from './label/label.atom';
6
+ export * from './command-empty/command-empty.atom';
7
+ export * from './command-group/command-group.atom';
8
+ export * from './command-item/command-item.atom';
9
+ export * from './command-list/command-list.atom';
10
+ export * from './command-separator/command-separator.atom';
@@ -0,0 +1,34 @@
1
+ /* eslint-disable lit/no-value-attribute */
2
+ import { LitElement, html, css } from 'lit';
3
+ import { property, customElement } from 'lit/decorators.js';
4
+ import { cn } from '@/helpers';
5
+ import { TWStyles } from '@/styles';
6
+ import { InputType } from './input.type';
7
+
8
+ @customElement('rtg-input')
9
+ export class Input extends LitElement {
10
+ @property({ type: Boolean }) disabled = false;
11
+
12
+ @property({ type: String }) type: InputType = 'text';
13
+
14
+ @property({ type: String }) placeholder = '';
15
+
16
+ @property({ type: String }) defaultValue = '';
17
+
18
+ static styles = [css``, TWStyles];
19
+
20
+ render() {
21
+ return html`
22
+ <input
23
+ type="${this.type}"
24
+ placeholder="${this.placeholder}"
25
+ ?disabled=${this.disabled}
26
+ class="${cn(
27
+ 'flex h-8 w-full rounded-sm border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
28
+ this.className
29
+ )}"
30
+ value="${this.defaultValue}"
31
+ />
32
+ `;
33
+ }
34
+ }
@@ -0,0 +1,89 @@
1
+ import { html } from 'lit';
2
+ import { Meta, StoryFn } from '@storybook/web-components';
3
+ import './input.atom';
4
+ import '../label/label.atom';
5
+ import '../button/button.atom';
6
+
7
+ export default {
8
+ title: 'Components/Input',
9
+ component: 'rtg-input',
10
+ tags: ['autodocs'],
11
+ argTypes: {
12
+ disabled: { control: 'boolean' },
13
+ type: { control: 'text' },
14
+ placeholder: { control: 'text' },
15
+ defaultValue: { control: 'text' },
16
+ },
17
+ } as Meta;
18
+
19
+ const InputTemplate: StoryFn = args =>
20
+ html`<rtg-input ...=${args}></rtg-input>`;
21
+ const TemplateWithLabel: StoryFn = args => html`
22
+ <rtg-label for="picture">${args.label}</rtg-label>
23
+ <rtg-input
24
+ type=${args.type}
25
+ ?disabled=${args.disabled}
26
+ placeholder=${args.placeholder}
27
+ ></rtg-input>
28
+ `;
29
+ const TemplateWithButton: StoryFn = args => html`
30
+ <div style="display:flex">
31
+ <rtg-input
32
+ id=${args.id}
33
+ type=${args.type}
34
+ placeholder=${args.placeholder}
35
+ class="min-w-80"
36
+ ></rtg-input>
37
+ <rtg-button
38
+ style="margin-inline-start:4px"
39
+ size="default"
40
+ onclick="javascript:alert('Hello!')"
41
+ >${args.ButtonLabel}</rtg-button
42
+ >
43
+ </div>
44
+ `;
45
+
46
+ export const Default = InputTemplate.bind({});
47
+ Default.args = {
48
+ disabled: false,
49
+ type: 'text',
50
+ placeholder: 'Enter text',
51
+ defaultValue: '',
52
+ };
53
+
54
+ export const Email = TemplateWithLabel.bind({});
55
+ Email.args = {
56
+ label: 'Email address',
57
+ disabled: false,
58
+ type: 'email',
59
+ placeholder: 'Enter email',
60
+ defaultValue: '',
61
+ };
62
+
63
+ export const Password = TemplateWithLabel.bind({});
64
+ Password.args = {
65
+ label: 'Password',
66
+ disabled: false,
67
+ type: 'password',
68
+ placeholder: 'Enter password',
69
+ defaultValue: '',
70
+ };
71
+
72
+ export const File = TemplateWithLabel.bind({});
73
+ File.args = {
74
+ disabled: false,
75
+ type: 'file',
76
+ label: 'Picture',
77
+ placeholder: '',
78
+ defaultValue: '',
79
+ };
80
+
81
+ export const InputWithButton = TemplateWithButton.bind({});
82
+ InputWithButton.args = {
83
+ id: 'id',
84
+ ButtonLabel: 'Subscribe',
85
+ disabled: false,
86
+ type: 'email',
87
+ placeholder: 'Email',
88
+ defaultValue: '',
89
+ };
@@ -0,0 +1,24 @@
1
+ export type InputType =
2
+ | 'hidden'
3
+ | 'text'
4
+ | 'search'
5
+ | 'tel'
6
+ | 'url'
7
+ | 'email'
8
+ | 'password'
9
+ | 'datetime'
10
+ | 'date'
11
+ | 'month'
12
+ | 'week'
13
+ | 'time'
14
+ | 'datetime-local'
15
+ | 'number'
16
+ | 'range'
17
+ | 'color'
18
+ | 'checkbox'
19
+ | 'radio'
20
+ | 'file'
21
+ | 'submit'
22
+ | 'image'
23
+ | 'reset'
24
+ | 'button';
@@ -0,0 +1,40 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { property, customElement } from 'lit/decorators.js';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '@/helpers';
5
+ import { TWStyles } from '@/styles';
6
+ import { labelStyle } from './label.style';
7
+
8
+ @customElement('rtg-label')
9
+ export class Label extends LitElement {
10
+ static labelVariants = labelStyle;
11
+
12
+ @property({ type: String }) for = '';
13
+
14
+ static styles = [css``, TWStyles];
15
+
16
+ private _onClick(e: Event) {
17
+ if (e.defaultPrevented) return;
18
+ const target = document.getElementById(this.for);
19
+ if (target) {
20
+ target.click();
21
+ }
22
+ }
23
+
24
+ render() {
25
+ return html`
26
+ <label
27
+ for="${this.for}"
28
+ @click="${this._onClick}"
29
+ @keydown="${this._onClick}"
30
+ class="${cn(
31
+ Label.labelVariants({
32
+ className: this.className,
33
+ })
34
+ )}"
35
+ >
36
+ <slot></slot>
37
+ </label>
38
+ `;
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ import { html } from 'lit';
2
+ import { Meta, StoryFn } from '@storybook/web-components';
3
+ import './label.atom';
4
+
5
+ export default {
6
+ title: 'Components/Label',
7
+ component: 'rtg-label',
8
+ tags: ['autodocs'],
9
+ } as Meta;
10
+
11
+ const Template: StoryFn = (args: any) =>
12
+ html` <rtg-label for=${args.for}>${args.label}</rtg-label>`;
13
+
14
+ export const Default = Template.bind({});
15
+ Default.args = {
16
+ for: 'id',
17
+ label: 'Email address',
18
+ };
@@ -0,0 +1,5 @@
1
+ import { cva } from 'class-variance-authority';
2
+
3
+ export const labelStyle = cva(
4
+ 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
5
+ );