@nuralyui/button 0.0.13 → 0.0.14
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/button.component.d.ts +13 -18
- package/button.component.d.ts.map +1 -1
- package/button.component.js +89 -101
- package/button.component.js.map +1 -1
- package/mixins/index.d.ts +14 -0
- package/mixins/index.d.ts.map +1 -0
- package/mixins/index.js +10 -0
- package/mixins/index.js.map +1 -0
- package/mixins/keyboard-mixin.d.ts +52 -0
- package/mixins/keyboard-mixin.d.ts.map +1 -0
- package/mixins/keyboard-mixin.js +78 -0
- package/mixins/keyboard-mixin.js.map +1 -0
- package/mixins/link-mixin.d.ts +67 -0
- package/mixins/link-mixin.d.ts.map +1 -0
- package/mixins/link-mixin.js +87 -0
- package/mixins/link-mixin.js.map +1 -0
- package/mixins/ripple-mixin.d.ts +53 -0
- package/mixins/ripple-mixin.d.ts.map +1 -0
- package/mixins/ripple-mixin.js +77 -0
- package/mixins/ripple-mixin.js.map +1 -0
- package/package.json +1 -1
package/button.component.d.ts
CHANGED
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { LitElement } from 'lit';
|
|
7
7
|
import { ButtonType, ButtonShape, IconPosition } from './button.types.js';
|
|
8
|
-
declare const NrButtonElement_base: (new (...args: any[]) => import("../../shared/dependency-mixin.js").DependencyAware) & (new (...args: any[]) => import("../../shared/theme-mixin.js").ThemeAware) & typeof LitElement;
|
|
8
|
+
declare const NrButtonElement_base: (new (...args: any[]) => import("./mixins/ripple-mixin.js").RippleCapable) & (new (...args: any[]) => import("./mixins/keyboard-mixin.js").KeyboardCapable) & (new (...args: any[]) => import("./mixins/link-mixin.js").LinkCapable) & (new (...args: any[]) => import("../../shared/dependency-mixin.js").DependencyAware) & (new (...args: any[]) => import("../../shared/theme-mixin.js").ThemeAware) & (new (...args: any[]) => import("../../shared/event-handler-mixin.js").EventHandlerCapable) & typeof LitElement;
|
|
9
|
+
/**
|
|
10
|
+
* - NuralyUIBaseMixin: Core functionality (theme, dependencies, events)
|
|
11
|
+
* - RippleMixin: Ripple effect handling
|
|
12
|
+
* - KeyboardMixin: Keyboard interaction (Enter/Space activation)
|
|
13
|
+
* - LinkMixin: Link-specific behavior for ButtonType.Link
|
|
14
|
+
*/
|
|
9
15
|
export declare class NrButtonElement extends NrButtonElement_base {
|
|
10
16
|
disabled: boolean;
|
|
11
17
|
loading: boolean;
|
|
@@ -19,9 +25,11 @@ export declare class NrButtonElement extends NrButtonElement_base {
|
|
|
19
25
|
href: string;
|
|
20
26
|
target: string;
|
|
21
27
|
ripple: boolean;
|
|
28
|
+
buttonAriaLabel: string;
|
|
29
|
+
ariaDescribedBy: string;
|
|
30
|
+
htmlType: string;
|
|
22
31
|
/**
|
|
23
32
|
* Required components that must be registered for this component to work properly
|
|
24
|
-
* Can be overridden by parent implementations
|
|
25
33
|
*/
|
|
26
34
|
requiredComponents: string[];
|
|
27
35
|
/**
|
|
@@ -29,16 +37,9 @@ export declare class NrButtonElement extends NrButtonElement_base {
|
|
|
29
37
|
*/
|
|
30
38
|
connectedCallback(): void;
|
|
31
39
|
/**
|
|
32
|
-
* Get
|
|
33
|
-
*/
|
|
34
|
-
private getElementTag;
|
|
35
|
-
/**
|
|
36
|
-
* Get attributes for accessibility and functionality
|
|
40
|
+
* Get common attributes for both button and anchor elements
|
|
37
41
|
*/
|
|
38
|
-
private
|
|
39
|
-
buttonAriaLabel: string;
|
|
40
|
-
ariaDescribedBy: string;
|
|
41
|
-
htmlType: string;
|
|
42
|
+
private getCommonAttributes;
|
|
42
43
|
/**
|
|
43
44
|
* Renders an icon if the hy-icon component is available
|
|
44
45
|
* @param iconName - The name of the icon to render
|
|
@@ -46,13 +47,7 @@ export declare class NrButtonElement extends NrButtonElement_base {
|
|
|
46
47
|
*/
|
|
47
48
|
private renderIcon;
|
|
48
49
|
/**
|
|
49
|
-
*
|
|
50
|
-
* @param event - The click event
|
|
51
|
-
*/
|
|
52
|
-
private createRipple;
|
|
53
|
-
/**
|
|
54
|
-
* Handle click events with ripple effect
|
|
55
|
-
* @param event - The click event
|
|
50
|
+
* Handle comprehensive click events with proper event dispatching
|
|
56
51
|
*/
|
|
57
52
|
private handleClick;
|
|
58
53
|
render(): import("lit").TemplateResult<1>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.component.d.ts","sourceRoot":"","sources":["../../../src/components/button/button.component.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,UAAU,EAAW,MAAM,KAAK,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAgB,YAAY,EAAE,MAAM,mBAAmB,CAAC;;
|
|
1
|
+
{"version":3,"file":"button.component.d.ts","sourceRoot":"","sources":["../../../src/components/button/button.component.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,UAAU,EAAW,MAAM,KAAK,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAgB,YAAY,EAAE,MAAM,mBAAmB,CAAC;;AAKxF;;;;;GAKG;AACH,qBACa,eAAgB,SAAQ,oBAMpC;IAGU,QAAQ,UAAS;IAG1B,OAAO,UAAS;IAGhB,IAAI,SAAgB;IAGX,IAAI,EAAE,UAAU,CAAsB;IAG/C,KAAK,EAAE,WAAW,CAAuB;IAGzC,KAAK,UAAS;IAGd,MAAM,UAAS;IAIf,IAAI,EAAE,MAAM,EAAE,CAAM;IAGpB,YAAY,eAAqB;IAIxB,IAAI,SAAgB;IAGpB,MAAM,SAAgB;IAItB,MAAM,UAAQ;IAIvB,eAAe,SAAgB;IAG/B,eAAe,SAAgB;IAG/B,QAAQ,SAAgB;IAExB;;OAEG;IACM,kBAAkB,WAAe;IAE1C;;OAEG;IACM,iBAAiB;IAK1B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAgB3B;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAWlB;;OAEG;IACH,OAAO,CAAC,WAAW;IA4BV,MAAM;IA8Df,OAAgB,MAAM,4BAAU;CACjC"}
|
package/button.component.js
CHANGED
|
@@ -14,9 +14,17 @@ import { customElement, property } from 'lit/decorators.js';
|
|
|
14
14
|
import { EMPTY_STRING } from './button.types.js';
|
|
15
15
|
import { styles } from './button.style.js';
|
|
16
16
|
import { NuralyUIBaseMixin } from '../../shared/base-mixin.js';
|
|
17
|
-
|
|
17
|
+
import { RippleMixin, KeyboardMixin, LinkMixin } from './mixins/index.js';
|
|
18
|
+
/**
|
|
19
|
+
* - NuralyUIBaseMixin: Core functionality (theme, dependencies, events)
|
|
20
|
+
* - RippleMixin: Ripple effect handling
|
|
21
|
+
* - KeyboardMixin: Keyboard interaction (Enter/Space activation)
|
|
22
|
+
* - LinkMixin: Link-specific behavior for ButtonType.Link
|
|
23
|
+
*/
|
|
24
|
+
let NrButtonElement = class NrButtonElement extends RippleMixin(KeyboardMixin(LinkMixin(NuralyUIBaseMixin(LitElement)))) {
|
|
18
25
|
constructor() {
|
|
19
26
|
super(...arguments);
|
|
27
|
+
// Button state properties
|
|
20
28
|
this.disabled = false;
|
|
21
29
|
this.loading = false;
|
|
22
30
|
this.size = EMPTY_STRING;
|
|
@@ -24,19 +32,22 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
|
|
|
24
32
|
this.shape = "default" /* ButtonShape.Default */;
|
|
25
33
|
this.block = false;
|
|
26
34
|
this.dashed = false;
|
|
35
|
+
// Icon properties
|
|
27
36
|
this.icon = [];
|
|
28
37
|
this.iconPosition = "left" /* IconPosition.Left */;
|
|
38
|
+
// Link properties (inherited from LinkMixin)
|
|
29
39
|
this.href = EMPTY_STRING;
|
|
30
40
|
this.target = EMPTY_STRING;
|
|
41
|
+
// Ripple property (inherited from RippleMixin)
|
|
31
42
|
this.ripple = true;
|
|
43
|
+
// Accessibility properties
|
|
44
|
+
this.buttonAriaLabel = EMPTY_STRING;
|
|
45
|
+
this.ariaDescribedBy = EMPTY_STRING;
|
|
46
|
+
this.htmlType = EMPTY_STRING;
|
|
32
47
|
/**
|
|
33
48
|
* Required components that must be registered for this component to work properly
|
|
34
|
-
* Can be overridden by parent implementations
|
|
35
49
|
*/
|
|
36
50
|
this.requiredComponents = ['hy-icon'];
|
|
37
|
-
this.buttonAriaLabel = EMPTY_STRING;
|
|
38
|
-
this.ariaDescribedBy = EMPTY_STRING;
|
|
39
|
-
this.htmlType = EMPTY_STRING;
|
|
40
51
|
}
|
|
41
52
|
/**
|
|
42
53
|
* Check for required dependencies when component is connected to DOM
|
|
@@ -46,44 +57,22 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
|
|
|
46
57
|
this.validateDependencies();
|
|
47
58
|
}
|
|
48
59
|
/**
|
|
49
|
-
* Get
|
|
50
|
-
*/
|
|
51
|
-
getElementTag() {
|
|
52
|
-
return this.type === "link" /* ButtonType.Link */ && this.href ? 'a' : 'button';
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Get attributes for accessibility and functionality
|
|
60
|
+
* Get common attributes for both button and anchor elements
|
|
56
61
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
'?disabled': this.disabled && this.type !== "link" /* ButtonType.Link */,
|
|
62
|
+
getCommonAttributes() {
|
|
63
|
+
return {
|
|
60
64
|
'data-type': this.type,
|
|
61
65
|
'data-shape': this.shape,
|
|
62
|
-
'data-size': this.size
|
|
66
|
+
'data-size': this.size || nothing,
|
|
63
67
|
'data-state': this.loading ? 'loading' : nothing,
|
|
64
68
|
'data-theme': this.currentTheme,
|
|
65
69
|
'data-block': this.block ? 'true' : nothing,
|
|
66
70
|
'class': this.dashed ? 'button-dashed' : '',
|
|
67
|
-
'role': this.type === "link" /* ButtonType.Link */ ? 'link' : 'button',
|
|
68
71
|
'aria-disabled': this.disabled ? 'true' : 'false',
|
|
69
72
|
'aria-label': this.buttonAriaLabel || nothing,
|
|
70
73
|
'aria-describedby': this.ariaDescribedBy || nothing,
|
|
74
|
+
'tabindex': this.disabled ? '-1' : '0'
|
|
71
75
|
};
|
|
72
|
-
// Add link-specific attributes
|
|
73
|
-
if (this.type === "link" /* ButtonType.Link */ && this.href) {
|
|
74
|
-
attributes.href = this.href;
|
|
75
|
-
if (this.target) {
|
|
76
|
-
attributes.target = this.target;
|
|
77
|
-
}
|
|
78
|
-
if (this.target === '_blank') {
|
|
79
|
-
attributes.rel = 'noopener noreferrer';
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
// Add button-specific attributes
|
|
83
|
-
if (this.type !== "link" /* ButtonType.Link */) {
|
|
84
|
-
attributes.type = this.htmlType || 'button';
|
|
85
|
-
}
|
|
86
|
-
return attributes;
|
|
87
76
|
}
|
|
88
77
|
/**
|
|
89
78
|
* Renders an icon if the hy-icon component is available
|
|
@@ -99,90 +88,89 @@ let NrButtonElement = class NrButtonElement extends NuralyUIBaseMixin(LitElement
|
|
|
99
88
|
return html `<hy-icon name=${iconName}></hy-icon>`;
|
|
100
89
|
}
|
|
101
90
|
/**
|
|
102
|
-
*
|
|
103
|
-
* @param event - The click event
|
|
104
|
-
*/
|
|
105
|
-
createRipple(event) {
|
|
106
|
-
if (!this.ripple || this.disabled)
|
|
107
|
-
return;
|
|
108
|
-
const button = event.currentTarget;
|
|
109
|
-
const rect = button.getBoundingClientRect();
|
|
110
|
-
const size = Math.max(rect.width, rect.height);
|
|
111
|
-
const x = event.clientX - rect.left - size / 2;
|
|
112
|
-
const y = event.clientY - rect.top - size / 2;
|
|
113
|
-
const ripple = document.createElement('span');
|
|
114
|
-
ripple.className = 'ripple';
|
|
115
|
-
ripple.style.width = ripple.style.height = size + 'px';
|
|
116
|
-
ripple.style.left = x + 'px';
|
|
117
|
-
ripple.style.top = y + 'px';
|
|
118
|
-
// Remove any existing ripples
|
|
119
|
-
const existingRipples = button.querySelectorAll('.ripple');
|
|
120
|
-
existingRipples.forEach(r => r.remove());
|
|
121
|
-
button.appendChild(ripple);
|
|
122
|
-
// Remove ripple after animation
|
|
123
|
-
setTimeout(() => {
|
|
124
|
-
ripple.remove();
|
|
125
|
-
}, 600);
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Handle click events with ripple effect
|
|
129
|
-
* @param event - The click event
|
|
91
|
+
* Handle comprehensive click events with proper event dispatching
|
|
130
92
|
*/
|
|
131
93
|
handleClick(event) {
|
|
132
|
-
this.
|
|
94
|
+
if (this.disabled) {
|
|
95
|
+
event.preventDefault();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Use RippleMixin method
|
|
99
|
+
this.handleRippleClick(event);
|
|
100
|
+
// Handle link navigation if it's a link type
|
|
101
|
+
if (this.isLinkType()) {
|
|
102
|
+
this.dispatchCustomEvent('link-navigation', {
|
|
103
|
+
href: this.href,
|
|
104
|
+
target: this.target,
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
originalEvent: event
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
// Dispatch button event with metadata using EventHandlerMixin
|
|
110
|
+
this.dispatchEventWithMetadata('button-clicked', {
|
|
111
|
+
type: this.type,
|
|
112
|
+
disabled: this.disabled,
|
|
113
|
+
loading: this.loading,
|
|
114
|
+
href: this.href || null
|
|
115
|
+
});
|
|
133
116
|
}
|
|
134
117
|
render() {
|
|
135
|
-
var _a, _b
|
|
136
|
-
const elementTag = this.getElementTag();
|
|
137
|
-
const
|
|
118
|
+
var _a, _b;
|
|
119
|
+
const elementTag = this.getElementTag(); // From LinkMixin
|
|
120
|
+
const commonAttributes = this.getCommonAttributes();
|
|
121
|
+
const linkAttributes = this.getLinkAttributes(); // From LinkMixin
|
|
122
|
+
const content = html `
|
|
123
|
+
<span id="container">
|
|
124
|
+
${((_a = this.icon) === null || _a === void 0 ? void 0 : _a.length) ? this.renderIcon(this.icon[0]) : nothing}
|
|
125
|
+
<slot id="slot"></slot>
|
|
126
|
+
${((_b = this.icon) === null || _b === void 0 ? void 0 : _b.length) === 2 ? this.renderIcon(this.icon[1]) : nothing}
|
|
127
|
+
</span>
|
|
128
|
+
`;
|
|
138
129
|
if (elementTag === 'a') {
|
|
139
130
|
return html `
|
|
140
131
|
<a
|
|
141
|
-
href="${
|
|
142
|
-
target="${
|
|
143
|
-
rel="${
|
|
144
|
-
|
|
145
|
-
data-
|
|
146
|
-
data-
|
|
147
|
-
data-
|
|
148
|
-
data-
|
|
149
|
-
data-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
aria-disabled="${
|
|
153
|
-
aria-label="${
|
|
154
|
-
aria-describedby="${
|
|
132
|
+
href="${linkAttributes.href}"
|
|
133
|
+
target="${linkAttributes.target || nothing}"
|
|
134
|
+
rel="${linkAttributes.rel || nothing}"
|
|
135
|
+
role="${linkAttributes.role}"
|
|
136
|
+
data-type="${commonAttributes['data-type']}"
|
|
137
|
+
data-shape="${commonAttributes['data-shape']}"
|
|
138
|
+
data-size="${commonAttributes['data-size']}"
|
|
139
|
+
data-state="${commonAttributes['data-state']}"
|
|
140
|
+
data-theme="${commonAttributes['data-theme']}"
|
|
141
|
+
data-block="${commonAttributes['data-block']}"
|
|
142
|
+
class="${commonAttributes.class}"
|
|
143
|
+
aria-disabled="${this.disabled}"
|
|
144
|
+
aria-label="${this.buttonAriaLabel || nothing}"
|
|
145
|
+
aria-describedby="${this.ariaDescribedBy || nothing}"
|
|
146
|
+
tabindex="${this.disabled ? -1 : 0}"
|
|
147
|
+
@click="${this.handleClick}"
|
|
148
|
+
@keydown="${this.handleKeydown}"
|
|
155
149
|
>
|
|
156
|
-
|
|
157
|
-
${((_a = this.icon) === null || _a === void 0 ? void 0 : _a.length) ? this.renderIcon(this.icon[0]) : nothing}
|
|
158
|
-
<slot id="slot"></slot>
|
|
159
|
-
${((_b = this.icon) === null || _b === void 0 ? void 0 : _b.length) == 2 ? this.renderIcon(this.icon[1]) : nothing}
|
|
160
|
-
</span>
|
|
150
|
+
${content}
|
|
161
151
|
</a>
|
|
162
152
|
`;
|
|
163
153
|
}
|
|
164
154
|
return html `
|
|
165
155
|
<button
|
|
166
|
-
?disabled="${
|
|
167
|
-
type="${
|
|
168
|
-
|
|
169
|
-
data-
|
|
170
|
-
data-
|
|
171
|
-
data-
|
|
172
|
-
data-
|
|
173
|
-
data-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
aria-disabled="${
|
|
177
|
-
aria-label="${
|
|
178
|
-
aria-describedby="${
|
|
156
|
+
?disabled="${this.disabled}"
|
|
157
|
+
type="${(this.htmlType || 'button')}"
|
|
158
|
+
role="${linkAttributes.role}"
|
|
159
|
+
data-type="${commonAttributes['data-type']}"
|
|
160
|
+
data-shape="${commonAttributes['data-shape']}"
|
|
161
|
+
data-size="${commonAttributes['data-size']}"
|
|
162
|
+
data-state="${commonAttributes['data-state']}"
|
|
163
|
+
data-theme="${commonAttributes['data-theme']}"
|
|
164
|
+
data-block="${commonAttributes['data-block']}"
|
|
165
|
+
class="${commonAttributes.class}"
|
|
166
|
+
aria-disabled="${this.disabled}"
|
|
167
|
+
aria-label="${this.buttonAriaLabel || nothing}"
|
|
168
|
+
aria-describedby="${this.ariaDescribedBy || nothing}"
|
|
169
|
+
tabindex="${this.disabled ? -1 : 0}"
|
|
179
170
|
@click="${this.handleClick}"
|
|
171
|
+
@keydown="${this.handleKeydown}"
|
|
180
172
|
>
|
|
181
|
-
|
|
182
|
-
${((_c = this.icon) === null || _c === void 0 ? void 0 : _c.length) ? this.renderIcon(this.icon[0]) : nothing}
|
|
183
|
-
<slot id="slot"></slot>
|
|
184
|
-
${((_d = this.icon) === null || _d === void 0 ? void 0 : _d.length) == 2 ? this.renderIcon(this.icon[1]) : nothing}
|
|
185
|
-
</span>
|
|
173
|
+
${content}
|
|
186
174
|
</button>
|
|
187
175
|
`;
|
|
188
176
|
}
|
package/button.component.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"button.component.js","sourceRoot":"","sources":["../../../src/components/button/button.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ButtonType, ButtonShape, EMPTY_STRING, IconPosition } from './button.types.js';\nimport { styles } from './button.style.js';\nimport { NuralyUIBaseMixin } from '../../shared/base-mixin.js';\n\n@customElement('nr-button')\nexport class NrButtonElement extends NuralyUIBaseMixin(LitElement) {\n @property({type: Boolean})\n disabled = false;\n\n @property({type: Boolean})\n loading = false;\n\n @property({type: String})\n size = EMPTY_STRING;\n\n @property({type: String})\n type: ButtonType = ButtonType.Default;\n\n @property({type: String})\n shape: ButtonShape = ButtonShape.Default;\n\n @property({type: Boolean})\n block = false;\n\n @property({type: Boolean})\n dashed = false;\n\n @property({type: Array})\n icon: string[] = [];\n\n @property({reflect: true})\n iconPosition = IconPosition.Left;\n\n @property({type: String})\n href = EMPTY_STRING;\n\n @property({type: String})\n target = EMPTY_STRING;\n\n @property({type: Boolean})\n ripple = true;\n\n /**\n * Required components that must be registered for this component to work properly\n * Can be overridden by parent implementations\n */\n override requiredComponents = ['hy-icon'];\n\n /**\n * Check for required dependencies when component is connected to DOM\n */\n override connectedCallback() {\n super.connectedCallback();\n this.validateDependencies();\n }\n\n /**\n * Get the appropriate element tag based on button type\n */\n private getElementTag() {\n return this.type === ButtonType.Link && this.href ? 'a' : 'button';\n }\n\n /**\n * Get attributes for accessibility and functionality\n */\n private getElementAttributes() {\n const attributes: any = {\n '?disabled': this.disabled && this.type !== ButtonType.Link,\n 'data-type': this.type,\n 'data-shape': this.shape,\n 'data-size': this.size ? this.size : nothing,\n 'data-state': this.loading ? 'loading' : nothing,\n 'data-theme': this.currentTheme,\n 'data-block': this.block ? 'true' : nothing,\n 'class': this.dashed ? 'button-dashed' : '',\n 'role': this.type === ButtonType.Link ? 'link' : 'button',\n 'aria-disabled': this.disabled ? 'true' : 'false',\n 'aria-label': this.buttonAriaLabel || nothing,\n 'aria-describedby': this.ariaDescribedBy || nothing,\n };\n\n // Add link-specific attributes\n if (this.type === ButtonType.Link && this.href) {\n attributes.href = this.href;\n if (this.target) {\n attributes.target = this.target;\n }\n if (this.target === '_blank') {\n attributes.rel = 'noopener noreferrer';\n }\n }\n\n // Add button-specific attributes\n if (this.type !== ButtonType.Link) {\n attributes.type = this.htmlType || 'button';\n }\n\n return attributes;\n }\n\n @property({type: String})\n buttonAriaLabel = EMPTY_STRING;\n\n @property({type: String})\n ariaDescribedBy = EMPTY_STRING;\n\n @property({type: String})\n htmlType = EMPTY_STRING;\n\n /**\n * Renders an icon if the hy-icon component is available\n * @param iconName - The name of the icon to render\n * @returns TemplateResult or nothing\n */\n private renderIcon(iconName: string) {\n if (!this.isComponentAvailable('hy-icon')) {\n console.warn(\n `hy-icon component not found. Icon \"${iconName}\" will not be displayed. ` +\n `Please import hy-icon component.`\n );\n return nothing;\n }\n return html`<hy-icon name=${iconName}></hy-icon>`;\n }\n\n /**\n * Creates ripple effect on button click\n * @param event - The click event\n */\n private createRipple(event: MouseEvent) {\n if (!this.ripple || this.disabled) return;\n\n const button = event.currentTarget as HTMLElement;\n const rect = button.getBoundingClientRect();\n const size = Math.max(rect.width, rect.height);\n const x = event.clientX - rect.left - size / 2;\n const y = event.clientY - rect.top - size / 2;\n\n const ripple = document.createElement('span');\n ripple.className = 'ripple';\n ripple.style.width = ripple.style.height = size + 'px';\n ripple.style.left = x + 'px';\n ripple.style.top = y + 'px';\n\n // Remove any existing ripples\n const existingRipples = button.querySelectorAll('.ripple');\n existingRipples.forEach(r => r.remove());\n\n button.appendChild(ripple);\n\n // Remove ripple after animation\n setTimeout(() => {\n ripple.remove();\n }, 600);\n }\n\n /**\n * Handle click events with ripple effect\n * @param event - The click event\n */\n private handleClick(event: MouseEvent) {\n this.createRipple(event);\n }\n\n override render() {\n const elementTag = this.getElementTag();\n const attributes = this.getElementAttributes();\n \n if (elementTag === 'a') {\n return html`\n <a\n href=\"${attributes.href}\"\n target=\"${attributes.target || nothing}\"\n rel=\"${attributes.rel || nothing}\"\n data-type=\"${attributes['data-type']}\"\n data-shape=\"${attributes['data-shape']}\"\n data-size=\"${attributes['data-size']}\"\n data-state=\"${attributes['data-state']}\"\n data-theme=\"${attributes['data-theme']}\"\n data-block=\"${attributes['data-block']}\"\n class=\"${attributes.class}\"\n role=\"${attributes.role}\"\n aria-disabled=\"${attributes['aria-disabled']}\"\n aria-label=\"${attributes['aria-label']}\"\n aria-describedby=\"${attributes['aria-describedby']}\"\n >\n <span id=\"container\">\n ${this.icon?.length ? this.renderIcon(this.icon[0]) : nothing}\n <slot id=\"slot\"></slot>\n ${this.icon?.length == 2 ? this.renderIcon(this.icon[1]) : nothing}\n </span>\n </a>\n `;\n }\n \n return html`\n <button\n ?disabled=\"${attributes['?disabled']}\"\n type=\"${attributes.type || nothing}\"\n data-type=\"${attributes['data-type']}\"\n data-shape=\"${attributes['data-shape']}\"\n data-size=\"${attributes['data-size']}\"\n data-state=\"${attributes['data-state']}\"\n data-theme=\"${attributes['data-theme']}\"\n data-block=\"${attributes['data-block']}\"\n class=\"${attributes.class}\"\n role=\"${attributes.role}\"\n aria-disabled=\"${attributes['aria-disabled']}\"\n aria-label=\"${attributes['aria-label']}\"\n aria-describedby=\"${attributes['aria-describedby']}\"\n @click=\"${this.handleClick}\"\n >\n <span id=\"container\">\n ${this.icon?.length ? this.renderIcon(this.icon[0]) : nothing}\n <slot id=\"slot\"></slot>\n ${this.icon?.length == 2 ? this.renderIcon(this.icon[1]) : nothing}\n </span>\n </button>\n `;\n }\n static override styles = styles;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"button.component.js","sourceRoot":"","sources":["../../../src/components/button/button.component.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ButtonType, ButtonShape, EMPTY_STRING, IconPosition } from './button.types.js';\nimport { styles } from './button.style.js';\nimport { NuralyUIBaseMixin } from '../../shared/base-mixin.js';\nimport { RippleMixin, KeyboardMixin, LinkMixin } from './mixins/index.js';\n\n/**\n * - NuralyUIBaseMixin: Core functionality (theme, dependencies, events)\n * - RippleMixin: Ripple effect handling\n * - KeyboardMixin: Keyboard interaction (Enter/Space activation)\n * - LinkMixin: Link-specific behavior for ButtonType.Link\n */\n@customElement('nr-button')\nexport class NrButtonElement extends RippleMixin(\n KeyboardMixin(\n LinkMixin(\n NuralyUIBaseMixin(LitElement)\n )\n )\n) {\n // Button state properties\n @property({ type: Boolean })\n override disabled = false;\n\n @property({ type: Boolean })\n loading = false;\n\n @property({ type: String })\n size = EMPTY_STRING;\n\n @property({ type: String })\n override type: ButtonType = ButtonType.Default;\n\n @property({ type: String })\n shape: ButtonShape = ButtonShape.Default;\n\n @property({ type: Boolean })\n block = false;\n\n @property({ type: Boolean })\n dashed = false;\n\n // Icon properties\n @property({ type: Array })\n icon: string[] = [];\n\n @property({ reflect: true })\n iconPosition = IconPosition.Left;\n\n // Link properties (inherited from LinkMixin)\n @property({ type: String })\n override href = EMPTY_STRING;\n\n @property({ type: String })\n override target = EMPTY_STRING;\n\n // Ripple property (inherited from RippleMixin)\n @property({ type: Boolean })\n override ripple = true;\n\n // Accessibility properties\n @property({ type: String })\n buttonAriaLabel = EMPTY_STRING;\n\n @property({ type: String })\n ariaDescribedBy = EMPTY_STRING;\n\n @property({ type: String })\n htmlType = EMPTY_STRING;\n\n /**\n * Required components that must be registered for this component to work properly\n */\n override requiredComponents = ['hy-icon'];\n\n /**\n * Check for required dependencies when component is connected to DOM\n */\n override connectedCallback() {\n super.connectedCallback();\n this.validateDependencies();\n }\n\n /**\n * Get common attributes for both button and anchor elements\n */\n private getCommonAttributes() {\n return {\n 'data-type': this.type,\n 'data-shape': this.shape,\n 'data-size': this.size || nothing,\n 'data-state': this.loading ? 'loading' : nothing,\n 'data-theme': this.currentTheme,\n 'data-block': this.block ? 'true' : nothing,\n 'class': this.dashed ? 'button-dashed' : '',\n 'aria-disabled': this.disabled ? 'true' : 'false',\n 'aria-label': this.buttonAriaLabel || nothing,\n 'aria-describedby': this.ariaDescribedBy || nothing,\n 'tabindex': this.disabled ? '-1' : '0'\n };\n }\n\n /**\n * Renders an icon if the hy-icon component is available\n * @param iconName - The name of the icon to render\n * @returns TemplateResult or nothing\n */\n private renderIcon(iconName: string) {\n if (!this.isComponentAvailable('hy-icon')) {\n console.warn(\n `hy-icon component not found. Icon \"${iconName}\" will not be displayed. ` +\n `Please import hy-icon component.`\n );\n return nothing;\n }\n return html`<hy-icon name=${iconName}></hy-icon>`;\n }\n\n /**\n * Handle comprehensive click events with proper event dispatching\n */\n private handleClick(event: MouseEvent) {\n if (this.disabled) {\n event.preventDefault();\n return;\n }\n\n // Use RippleMixin method\n this.handleRippleClick(event);\n \n // Handle link navigation if it's a link type\n if (this.isLinkType()) {\n this.dispatchCustomEvent('link-navigation', {\n href: this.href,\n target: this.target,\n timestamp: Date.now(),\n originalEvent: event\n });\n }\n \n // Dispatch button event with metadata using EventHandlerMixin\n this.dispatchEventWithMetadata('button-clicked', {\n type: this.type,\n disabled: this.disabled,\n loading: this.loading,\n href: this.href || null\n });\n }\n\n override render() {\n const elementTag = this.getElementTag(); // From LinkMixin\n const commonAttributes = this.getCommonAttributes();\n const linkAttributes = this.getLinkAttributes(); // From LinkMixin\n \n const content = html`\n <span id=\"container\">\n ${this.icon?.length ? this.renderIcon(this.icon[0]) : nothing}\n <slot id=\"slot\"></slot>\n ${this.icon?.length === 2 ? this.renderIcon(this.icon[1]) : nothing}\n </span>\n `;\n \n if (elementTag === 'a') {\n return html`\n <a\n href=\"${linkAttributes.href}\"\n target=\"${linkAttributes.target || nothing}\"\n rel=\"${linkAttributes.rel || nothing}\"\n role=\"${linkAttributes.role}\"\n data-type=\"${commonAttributes['data-type']}\"\n data-shape=\"${commonAttributes['data-shape']}\"\n data-size=\"${commonAttributes['data-size']}\"\n data-state=\"${commonAttributes['data-state']}\"\n data-theme=\"${commonAttributes['data-theme']}\"\n data-block=\"${commonAttributes['data-block']}\"\n class=\"${commonAttributes.class}\"\n aria-disabled=\"${this.disabled}\"\n aria-label=\"${this.buttonAriaLabel || nothing}\"\n aria-describedby=\"${this.ariaDescribedBy || nothing}\"\n tabindex=\"${this.disabled ? -1 : 0}\"\n @click=\"${this.handleClick}\"\n @keydown=\"${this.handleKeydown}\"\n >\n ${content}\n </a>\n `;\n }\n \n return html`\n <button\n ?disabled=\"${this.disabled}\"\n type=\"${(this.htmlType || 'button') as 'button' | 'submit' | 'reset'}\"\n role=\"${linkAttributes.role}\"\n data-type=\"${commonAttributes['data-type']}\"\n data-shape=\"${commonAttributes['data-shape']}\"\n data-size=\"${commonAttributes['data-size']}\" \n data-state=\"${commonAttributes['data-state']}\"\n data-theme=\"${commonAttributes['data-theme']}\"\n data-block=\"${commonAttributes['data-block']}\"\n class=\"${commonAttributes.class}\"\n aria-disabled=\"${this.disabled}\"\n aria-label=\"${this.buttonAriaLabel || nothing}\"\n aria-describedby=\"${this.ariaDescribedBy || nothing}\"\n tabindex=\"${this.disabled ? -1 : 0}\"\n @click=\"${this.handleClick}\"\n @keydown=\"${this.handleKeydown}\"\n >\n ${content}\n </button>\n `;\n }\n static override styles = styles;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
export { RippleMixin, type RippleCapable } from './ripple-mixin.js';
|
|
7
|
+
export { KeyboardMixin, type KeyboardCapable } from './keyboard-mixin.js';
|
|
8
|
+
export { LinkMixin, type LinkCapable } from './link-mixin.js';
|
|
9
|
+
import type { RippleCapable } from './ripple-mixin.js';
|
|
10
|
+
import type { KeyboardCapable } from './keyboard-mixin.js';
|
|
11
|
+
import type { LinkCapable } from './link-mixin.js';
|
|
12
|
+
export interface ButtonMixinCapable extends RippleCapable, KeyboardCapable, LinkCapable {
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/button/mixins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGnD,MAAM,WAAW,kBAAmB,SAAQ,aAAa,EAAE,eAAe,EAAE,WAAW;CAAG"}
|
package/mixins/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
// Export all button-specific mixins
|
|
7
|
+
export { RippleMixin } from './ripple-mixin.js';
|
|
8
|
+
export { KeyboardMixin } from './keyboard-mixin.js';
|
|
9
|
+
export { LinkMixin } from './link-mixin.js';
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/button/mixins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oCAAoC;AACpC,OAAO,EAAE,WAAW,EAAsB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAwB,MAAM,qBAAqB,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAoB,MAAM,iBAAiB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\n// Export all button-specific mixins\nexport { RippleMixin, type RippleCapable } from './ripple-mixin.js';\nexport { KeyboardMixin, type KeyboardCapable } from './keyboard-mixin.js';\nexport { LinkMixin, type LinkCapable } from './link-mixin.js';\n\n// Import types for combined interface\nimport type { RippleCapable } from './ripple-mixin.js';\nimport type { KeyboardCapable } from './keyboard-mixin.js';\nimport type { LinkCapable } from './link-mixin.js';\n\n// Combined interface for button components using all mixins\nexport interface ButtonMixinCapable extends RippleCapable, KeyboardCapable, LinkCapable {}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { LitElement } from 'lit';
|
|
7
|
+
declare type Constructor<T = {}> = new (...args: any[]) => T;
|
|
8
|
+
/**
|
|
9
|
+
* Interface for components that support keyboard interaction
|
|
10
|
+
*/
|
|
11
|
+
export interface KeyboardCapable {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the component is disabled
|
|
14
|
+
*/
|
|
15
|
+
disabled: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Handle keyboard activation (Enter/Space)
|
|
18
|
+
*/
|
|
19
|
+
handleKeyboardActivation(event: KeyboardEvent): void;
|
|
20
|
+
/**
|
|
21
|
+
* Handle keydown events with proper focus management
|
|
22
|
+
*/
|
|
23
|
+
handleKeydown(event: KeyboardEvent): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Mixin that provides keyboard interaction capabilities for button-like components
|
|
27
|
+
* Handles Enter and Space key activation following ARIA best practices
|
|
28
|
+
*
|
|
29
|
+
* @param superClass - The base class to extend
|
|
30
|
+
* @returns Enhanced class with keyboard interaction capabilities
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* export class MyButton extends KeyboardMixin(LitElement) {
|
|
35
|
+
* @property({ type: Boolean }) disabled = false;
|
|
36
|
+
*
|
|
37
|
+
* render() {
|
|
38
|
+
* return html`
|
|
39
|
+
* <button
|
|
40
|
+
* @keydown="${this.handleKeydown}"
|
|
41
|
+
* tabindex="${this.disabled ? '-1' : '0'}"
|
|
42
|
+
* >
|
|
43
|
+
* <slot></slot>
|
|
44
|
+
* </button>
|
|
45
|
+
* `;
|
|
46
|
+
* }
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare const KeyboardMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<KeyboardCapable> & T;
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=keyboard-mixin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard-mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/button/mixins/keyboard-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,wBAAwB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,aAAa,wFAwDzB,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mixin that provides keyboard interaction capabilities for button-like components
|
|
8
|
+
* Handles Enter and Space key activation following ARIA best practices
|
|
9
|
+
*
|
|
10
|
+
* @param superClass - The base class to extend
|
|
11
|
+
* @returns Enhanced class with keyboard interaction capabilities
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* export class MyButton extends KeyboardMixin(LitElement) {
|
|
16
|
+
* @property({ type: Boolean }) disabled = false;
|
|
17
|
+
*
|
|
18
|
+
* render() {
|
|
19
|
+
* return html`
|
|
20
|
+
* <button
|
|
21
|
+
* @keydown="${this.handleKeydown}"
|
|
22
|
+
* tabindex="${this.disabled ? '-1' : '0'}"
|
|
23
|
+
* >
|
|
24
|
+
* <slot></slot>
|
|
25
|
+
* </button>
|
|
26
|
+
* `;
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const KeyboardMixin = (superClass) => {
|
|
32
|
+
class KeyboardMixinClass extends superClass {
|
|
33
|
+
/**
|
|
34
|
+
* Handle keyboard activation (Enter/Space keys)
|
|
35
|
+
* @param event - The keyboard event
|
|
36
|
+
*/
|
|
37
|
+
handleKeyboardActivation(event) {
|
|
38
|
+
if (this.disabled)
|
|
39
|
+
return;
|
|
40
|
+
// Check if EventHandlerMixin is available for proper key checking
|
|
41
|
+
const isActivationKey = typeof this.isActivationKey === 'function'
|
|
42
|
+
? this.isActivationKey(event)
|
|
43
|
+
: (event.key === 'Enter' || event.key === ' ');
|
|
44
|
+
if (isActivationKey) {
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
// Trigger click event for consistency
|
|
47
|
+
this.click();
|
|
48
|
+
// Dispatch custom keyboard activation event if EventHandling mixin is available
|
|
49
|
+
if (typeof this.dispatchCustomEvent === 'function') {
|
|
50
|
+
this.dispatchCustomEvent('keyboard-activation', {
|
|
51
|
+
key: event.key,
|
|
52
|
+
timestamp: Date.now(),
|
|
53
|
+
target: this
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Handle keydown events with proper disabled state checking
|
|
60
|
+
* @param event - The keyboard event
|
|
61
|
+
*/
|
|
62
|
+
handleKeydown(event) {
|
|
63
|
+
if (this.disabled) {
|
|
64
|
+
// Allow readonly navigation keys even when disabled
|
|
65
|
+
const isNavigationKey = typeof this.isReadonlyKeyAllowed === 'function'
|
|
66
|
+
? this.isReadonlyKeyAllowed(event)
|
|
67
|
+
: ['Tab', 'Shift', 'Escape', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key);
|
|
68
|
+
if (!isNavigationKey) {
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
this.handleKeyboardActivation(event);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return KeyboardMixinClass;
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=keyboard-mixin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyboard-mixin.js","sourceRoot":"","sources":["../../../../src/components/button/mixins/keyboard-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAoC,UAAa,EAAE,EAAE;IAChF,MAAM,kBAAmB,SAAQ,UAAU;QAIzC;;;WAGG;QACH,wBAAwB,CAAC,KAAoB;YAC3C,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAE1B,kEAAkE;YAClE,MAAM,eAAe,GAAG,OAAQ,IAAY,CAAC,eAAe,KAAK,UAAU;gBACzE,CAAC,CAAE,IAAY,CAAC,eAAe,CAAC,KAAK,CAAC;gBACtC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YAEjD,IAAI,eAAe,EAAE;gBACnB,KAAK,CAAC,cAAc,EAAE,CAAC;gBAEvB,sCAAsC;gBACtC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAEb,gFAAgF;gBAChF,IAAI,OAAQ,IAAY,CAAC,mBAAmB,KAAK,UAAU,EAAE;oBAC1D,IAAY,CAAC,mBAAmB,CAAC,qBAAqB,EAAE;wBACvD,GAAG,EAAE,KAAK,CAAC,GAAG;wBACd,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;wBACrB,MAAM,EAAE,IAAI;qBACb,CAAC,CAAC;iBACJ;aACF;QACH,CAAC;QAED;;;WAGG;QACH,aAAa,CAAC,KAAoB;YAChC,IAAI,IAAI,CAAC,QAAQ,EAAE;gBACjB,oDAAoD;gBACpD,MAAM,eAAe,GAAG,OAAQ,IAAY,CAAC,oBAAoB,KAAK,UAAU;oBAC9E,CAAC,CAAE,IAAY,CAAC,oBAAoB,CAAC,KAAK,CAAC;oBAC3C,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAErH,IAAI,CAAC,eAAe,EAAE;oBACpB,KAAK,CAAC,cAAc,EAAE,CAAC;oBACvB,OAAO;iBACR;aACF;YAED,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC;QACvC,CAAC;KACF;IAED,OAAO,kBAAsD,CAAC;AAChE,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement } from 'lit';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Interface for components that support keyboard interaction\n */\nexport interface KeyboardCapable {\n /**\n * Whether the component is disabled\n */\n disabled: boolean;\n \n /**\n * Handle keyboard activation (Enter/Space)\n */\n handleKeyboardActivation(event: KeyboardEvent): void;\n \n /**\n * Handle keydown events with proper focus management\n */\n handleKeydown(event: KeyboardEvent): void;\n}\n\n/**\n * Mixin that provides keyboard interaction capabilities for button-like components\n * Handles Enter and Space key activation following ARIA best practices\n * \n * @param superClass - The base class to extend\n * @returns Enhanced class with keyboard interaction capabilities\n * \n * @example\n * ```typescript\n * export class MyButton extends KeyboardMixin(LitElement) {\n * @property({ type: Boolean }) disabled = false;\n * \n * render() {\n * return html`\n * <button \n * @keydown=\"${this.handleKeydown}\"\n * tabindex=\"${this.disabled ? '-1' : '0'}\"\n * >\n * <slot></slot>\n * </button>\n * `;\n * }\n * }\n * ```\n */\nexport const KeyboardMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class KeyboardMixinClass extends superClass implements KeyboardCapable {\n \n declare disabled: boolean;\n \n /**\n * Handle keyboard activation (Enter/Space keys)\n * @param event - The keyboard event\n */\n handleKeyboardActivation(event: KeyboardEvent): void {\n if (this.disabled) return;\n \n // Check if EventHandlerMixin is available for proper key checking\n const isActivationKey = typeof (this as any).isActivationKey === 'function'\n ? (this as any).isActivationKey(event)\n : (event.key === 'Enter' || event.key === ' ');\n \n if (isActivationKey) {\n event.preventDefault();\n \n // Trigger click event for consistency\n this.click();\n \n // Dispatch custom keyboard activation event if EventHandling mixin is available\n if (typeof (this as any).dispatchCustomEvent === 'function') {\n (this as any).dispatchCustomEvent('keyboard-activation', {\n key: event.key,\n timestamp: Date.now(),\n target: this\n });\n }\n }\n }\n\n /**\n * Handle keydown events with proper disabled state checking\n * @param event - The keyboard event\n */\n handleKeydown(event: KeyboardEvent): void {\n if (this.disabled) {\n // Allow readonly navigation keys even when disabled\n const isNavigationKey = typeof (this as any).isReadonlyKeyAllowed === 'function'\n ? (this as any).isReadonlyKeyAllowed(event)\n : ['Tab', 'Shift', 'Escape', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key);\n \n if (!isNavigationKey) {\n event.preventDefault();\n return;\n }\n }\n \n this.handleKeyboardActivation(event);\n }\n }\n\n return KeyboardMixinClass as Constructor<KeyboardCapable> & T;\n};\n"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { LitElement } from 'lit';
|
|
7
|
+
import { ButtonType } from '../button.types.js';
|
|
8
|
+
declare type Constructor<T = {}> = new (...args: any[]) => T;
|
|
9
|
+
/**
|
|
10
|
+
* Interface for components that support link behavior
|
|
11
|
+
*/
|
|
12
|
+
export interface LinkCapable {
|
|
13
|
+
/**
|
|
14
|
+
* Button type that determines if it should render as link
|
|
15
|
+
*/
|
|
16
|
+
type: ButtonType;
|
|
17
|
+
/**
|
|
18
|
+
* URL for link buttons
|
|
19
|
+
*/
|
|
20
|
+
href: string;
|
|
21
|
+
/**
|
|
22
|
+
* Target attribute for link buttons
|
|
23
|
+
*/
|
|
24
|
+
target: string;
|
|
25
|
+
/**
|
|
26
|
+
* Get the appropriate element tag (button or a)
|
|
27
|
+
*/
|
|
28
|
+
getElementTag(): string;
|
|
29
|
+
/**
|
|
30
|
+
* Get link-specific attributes
|
|
31
|
+
*/
|
|
32
|
+
getLinkAttributes(): Record<string, any>;
|
|
33
|
+
/**
|
|
34
|
+
* Check if component should render as a link
|
|
35
|
+
*/
|
|
36
|
+
isLinkType(): boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Mixin that provides link behavior for button components
|
|
40
|
+
* Handles the distinction between button and anchor elements
|
|
41
|
+
*
|
|
42
|
+
* @param superClass - The base class to extend
|
|
43
|
+
* @returns Enhanced class with link capabilities
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* export class MyButton extends LinkMixin(LitElement) {
|
|
48
|
+
* @property({ type: String }) type = ButtonType.Default;
|
|
49
|
+
* @property({ type: String }) href = '';
|
|
50
|
+
* @property({ type: String }) target = '';
|
|
51
|
+
*
|
|
52
|
+
* render() {
|
|
53
|
+
* const tag = this.getElementTag();
|
|
54
|
+
* const attrs = this.getLinkAttributes();
|
|
55
|
+
*
|
|
56
|
+
* return html`
|
|
57
|
+
* <${tag} ...${attrs}>
|
|
58
|
+
* <slot></slot>
|
|
59
|
+
* </${tag}>
|
|
60
|
+
* `;
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare const LinkMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<LinkCapable> & T;
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=link-mixin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/button/mixins/link-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,IAAI,EAAE,UAAU,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,IAAI,MAAM,CAAC;IAExB;;OAEG;IACH,iBAAiB,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEzC;;OAEG;IACH,UAAU,IAAI,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,eAAO,MAAM,SAAS,oFAkErB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mixin that provides link behavior for button components
|
|
8
|
+
* Handles the distinction between button and anchor elements
|
|
9
|
+
*
|
|
10
|
+
* @param superClass - The base class to extend
|
|
11
|
+
* @returns Enhanced class with link capabilities
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* export class MyButton extends LinkMixin(LitElement) {
|
|
16
|
+
* @property({ type: String }) type = ButtonType.Default;
|
|
17
|
+
* @property({ type: String }) href = '';
|
|
18
|
+
* @property({ type: String }) target = '';
|
|
19
|
+
*
|
|
20
|
+
* render() {
|
|
21
|
+
* const tag = this.getElementTag();
|
|
22
|
+
* const attrs = this.getLinkAttributes();
|
|
23
|
+
*
|
|
24
|
+
* return html`
|
|
25
|
+
* <${tag} ...${attrs}>
|
|
26
|
+
* <slot></slot>
|
|
27
|
+
* </${tag}>
|
|
28
|
+
* `;
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const LinkMixin = (superClass) => {
|
|
34
|
+
class LinkMixinClass extends superClass {
|
|
35
|
+
/**
|
|
36
|
+
* Check if the button should render as a link
|
|
37
|
+
*/
|
|
38
|
+
isLinkType() {
|
|
39
|
+
return this.type === "link" /* ButtonType.Link */ && !!this.href;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get the appropriate element tag based on button type
|
|
43
|
+
*/
|
|
44
|
+
getElementTag() {
|
|
45
|
+
return this.isLinkType() ? 'a' : 'button';
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get link-specific attributes for anchor elements
|
|
49
|
+
*/
|
|
50
|
+
getLinkAttributes() {
|
|
51
|
+
const attributes = {};
|
|
52
|
+
if (this.isLinkType()) {
|
|
53
|
+
attributes.href = this.href;
|
|
54
|
+
if (this.target) {
|
|
55
|
+
attributes.target = this.target;
|
|
56
|
+
// Add security attributes for external links
|
|
57
|
+
if (this.target === '_blank') {
|
|
58
|
+
attributes.rel = 'noopener noreferrer';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
attributes.role = 'link';
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
attributes.role = 'button';
|
|
65
|
+
}
|
|
66
|
+
return attributes;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Handle link navigation with proper event dispatching
|
|
70
|
+
*/
|
|
71
|
+
handleLinkNavigation(event) {
|
|
72
|
+
if (this.isLinkType()) {
|
|
73
|
+
// Dispatch custom navigation event if EventHandling mixin is available
|
|
74
|
+
if (typeof this.dispatchCustomEvent === 'function') {
|
|
75
|
+
this.dispatchCustomEvent('link-navigation', {
|
|
76
|
+
href: this.href,
|
|
77
|
+
target: this.target,
|
|
78
|
+
timestamp: Date.now(),
|
|
79
|
+
originalEvent: event
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return LinkMixinClass;
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=link-mixin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"link-mixin.js","sourceRoot":"","sources":["../../../../src/components/button/mixins/link-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0CH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAoC,UAAa,EAAE,EAAE;IAC5E,MAAM,cAAe,SAAQ,UAAU;QAMrC;;WAEG;QACH,UAAU;YACR,OAAO,IAAI,CAAC,IAAI,iCAAoB,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACtD,CAAC;QAED;;WAEG;QACH,aAAa;YACX,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5C,CAAC;QAED;;WAEG;QACH,iBAAiB;YACf,MAAM,UAAU,GAAwB,EAAE,CAAC;YAE3C,IAAI,IAAI,CAAC,UAAU,EAAE,EAAE;gBACrB,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBAE5B,IAAI,IAAI,CAAC,MAAM,EAAE;oBACf,UAAU,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;oBAEhC,6CAA6C;oBAC7C,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,EAAE;wBAC5B,UAAU,CAAC,GAAG,GAAG,qBAAqB,CAAC;qBACxC;iBACF;gBAED,UAAU,CAAC,IAAI,GAAG,MAAM,CAAC;aAC1B;iBAAM;gBACL,UAAU,CAAC,IAAI,GAAG,QAAQ,CAAC;aAC5B;YAED,OAAO,UAAU,CAAC;QACpB,CAAC;QAED;;WAEG;QACH,oBAAoB,CAAC,KAAY;YAC/B,IAAI,IAAI,CAAC,UAAU,EAAE,EAAE;gBACrB,uEAAuE;gBACvE,IAAI,OAAQ,IAAY,CAAC,mBAAmB,KAAK,UAAU,EAAE;oBAC1D,IAAY,CAAC,mBAAmB,CAAC,iBAAiB,EAAE;wBACnD,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,MAAM,EAAE,IAAI,CAAC,MAAM;wBACnB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;wBACrB,aAAa,EAAE,KAAK;qBACrB,CAAC,CAAC;iBACJ;aACF;QACH,CAAC;KACF;IAED,OAAO,cAA8C,CAAC;AACxD,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement } from 'lit';\nimport { ButtonType } from '../button.types.js';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Interface for components that support link behavior\n */\nexport interface LinkCapable {\n /**\n * Button type that determines if it should render as link\n */\n type: ButtonType;\n \n /**\n * URL for link buttons\n */\n href: string;\n \n /**\n * Target attribute for link buttons\n */\n target: string;\n \n /**\n * Get the appropriate element tag (button or a)\n */\n getElementTag(): string;\n \n /**\n * Get link-specific attributes\n */\n getLinkAttributes(): Record<string, any>;\n \n /**\n * Check if component should render as a link\n */\n isLinkType(): boolean;\n}\n\n/**\n * Mixin that provides link behavior for button components\n * Handles the distinction between button and anchor elements\n * \n * @param superClass - The base class to extend\n * @returns Enhanced class with link capabilities\n * \n * @example\n * ```typescript\n * export class MyButton extends LinkMixin(LitElement) {\n * @property({ type: String }) type = ButtonType.Default;\n * @property({ type: String }) href = '';\n * @property({ type: String }) target = '';\n * \n * render() {\n * const tag = this.getElementTag();\n * const attrs = this.getLinkAttributes();\n * \n * return html`\n * <${tag} ...${attrs}>\n * <slot></slot>\n * </${tag}>\n * `;\n * }\n * }\n * ```\n */\nexport const LinkMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class LinkMixinClass extends superClass implements LinkCapable {\n \n declare type: ButtonType;\n declare href: string;\n declare target: string;\n \n /**\n * Check if the button should render as a link\n */\n isLinkType(): boolean {\n return this.type === ButtonType.Link && !!this.href;\n }\n \n /**\n * Get the appropriate element tag based on button type\n */\n getElementTag(): string {\n return this.isLinkType() ? 'a' : 'button';\n }\n \n /**\n * Get link-specific attributes for anchor elements\n */\n getLinkAttributes(): Record<string, any> {\n const attributes: Record<string, any> = {};\n \n if (this.isLinkType()) {\n attributes.href = this.href;\n \n if (this.target) {\n attributes.target = this.target;\n \n // Add security attributes for external links\n if (this.target === '_blank') {\n attributes.rel = 'noopener noreferrer';\n }\n }\n \n attributes.role = 'link';\n } else {\n attributes.role = 'button';\n }\n \n return attributes;\n }\n \n /**\n * Handle link navigation with proper event dispatching\n */\n handleLinkNavigation(event: Event): void {\n if (this.isLinkType()) {\n // Dispatch custom navigation event if EventHandling mixin is available\n if (typeof (this as any).dispatchCustomEvent === 'function') {\n (this as any).dispatchCustomEvent('link-navigation', {\n href: this.href,\n target: this.target,\n timestamp: Date.now(),\n originalEvent: event\n });\n }\n }\n }\n }\n\n return LinkMixinClass as Constructor<LinkCapable> & T;\n};\n"]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
import { LitElement } from 'lit';
|
|
7
|
+
declare type Constructor<T = {}> = new (...args: any[]) => T;
|
|
8
|
+
/**
|
|
9
|
+
* Interface for components that support ripple effect
|
|
10
|
+
*/
|
|
11
|
+
export interface RippleCapable {
|
|
12
|
+
/**
|
|
13
|
+
* Whether ripple effect is enabled
|
|
14
|
+
*/
|
|
15
|
+
ripple: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the component is disabled (affects ripple)
|
|
18
|
+
*/
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Create ripple effect at click position
|
|
22
|
+
*/
|
|
23
|
+
createRipple(event: MouseEvent): void;
|
|
24
|
+
/**
|
|
25
|
+
* Handle click events with ripple effect
|
|
26
|
+
*/
|
|
27
|
+
handleRippleClick(event: MouseEvent): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Mixin that provides ripple effect functionality for button-like components
|
|
31
|
+
*
|
|
32
|
+
* @param superClass - The base class to extend
|
|
33
|
+
* @returns Enhanced class with ripple effect capabilities
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* export class MyButton extends RippleMixin(LitElement) {
|
|
38
|
+
* @property({ type: Boolean }) ripple = true;
|
|
39
|
+
* @property({ type: Boolean }) disabled = false;
|
|
40
|
+
*
|
|
41
|
+
* render() {
|
|
42
|
+
* return html`
|
|
43
|
+
* <button @click="${this.handleRippleClick}">
|
|
44
|
+
* <slot></slot>
|
|
45
|
+
* </button>
|
|
46
|
+
* `;
|
|
47
|
+
* }
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare const RippleMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<RippleCapable> & T;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=ripple-mixin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ripple-mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/button/mixins/ripple-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEjC,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEtC;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;CAC5C;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,WAAW,sFA2DvB,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mixin that provides ripple effect functionality for button-like components
|
|
8
|
+
*
|
|
9
|
+
* @param superClass - The base class to extend
|
|
10
|
+
* @returns Enhanced class with ripple effect capabilities
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* export class MyButton extends RippleMixin(LitElement) {
|
|
15
|
+
* @property({ type: Boolean }) ripple = true;
|
|
16
|
+
* @property({ type: Boolean }) disabled = false;
|
|
17
|
+
*
|
|
18
|
+
* render() {
|
|
19
|
+
* return html`
|
|
20
|
+
* <button @click="${this.handleRippleClick}">
|
|
21
|
+
* <slot></slot>
|
|
22
|
+
* </button>
|
|
23
|
+
* `;
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export const RippleMixin = (superClass) => {
|
|
29
|
+
class RippleMixinClass extends superClass {
|
|
30
|
+
/**
|
|
31
|
+
* Creates ripple effect on button click
|
|
32
|
+
* @param event - The click event
|
|
33
|
+
*/
|
|
34
|
+
createRipple(event) {
|
|
35
|
+
if (!this.ripple || this.disabled)
|
|
36
|
+
return;
|
|
37
|
+
const button = event.currentTarget;
|
|
38
|
+
const rect = button.getBoundingClientRect();
|
|
39
|
+
const size = Math.max(rect.width, rect.height);
|
|
40
|
+
const x = event.clientX - rect.left - size / 2;
|
|
41
|
+
const y = event.clientY - rect.top - size / 2;
|
|
42
|
+
const ripple = document.createElement('span');
|
|
43
|
+
ripple.className = 'ripple';
|
|
44
|
+
ripple.style.width = ripple.style.height = size + 'px';
|
|
45
|
+
ripple.style.left = x + 'px';
|
|
46
|
+
ripple.style.top = y + 'px';
|
|
47
|
+
// Remove any existing ripples
|
|
48
|
+
const existingRipples = button.querySelectorAll('.ripple');
|
|
49
|
+
existingRipples.forEach(r => r.remove());
|
|
50
|
+
button.appendChild(ripple);
|
|
51
|
+
// Remove ripple after animation
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
ripple.remove();
|
|
54
|
+
}, 600);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Handle click events with ripple effect and dispatch custom event
|
|
58
|
+
* @param event - The click event
|
|
59
|
+
*/
|
|
60
|
+
handleRippleClick(event) {
|
|
61
|
+
this.createRipple(event);
|
|
62
|
+
// Dispatch custom button click event if EventHandling mixin is available
|
|
63
|
+
if (typeof this.dispatchCustomEvent === 'function') {
|
|
64
|
+
this.dispatchCustomEvent('button-click', {
|
|
65
|
+
disabled: this.disabled,
|
|
66
|
+
timestamp: Date.now(),
|
|
67
|
+
coordinates: {
|
|
68
|
+
x: event.clientX,
|
|
69
|
+
y: event.clientY
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return RippleMixinClass;
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=ripple-mixin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ripple-mixin.js","sourceRoot":"","sources":["../../../../src/components/button/mixins/ripple-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA+BH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAoC,UAAa,EAAE,EAAE;IAC9E,MAAM,gBAAiB,SAAQ,UAAU;QAKvC;;;WAGG;QACH,YAAY,CAAC,KAAiB;YAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ;gBAAE,OAAO;YAE1C,MAAM,MAAM,GAAG,KAAK,CAAC,aAA4B,CAAC;YAClD,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;YAC/C,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC;YAE9C,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAC9C,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC;YAC5B,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;YACvD,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC;YAE5B,8BAA8B;YAC9B,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAC3D,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAEzC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAE3B,gCAAgC;YAChC,UAAU,CAAC,GAAG,EAAE;gBACd,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QAED;;;WAGG;QACH,iBAAiB,CAAC,KAAiB;YACjC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;YAEzB,yEAAyE;YACzE,IAAI,OAAQ,IAAY,CAAC,mBAAmB,KAAK,UAAU,EAAE;gBAC1D,IAAY,CAAC,mBAAmB,CAAC,cAAc,EAAE;oBAChD,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,WAAW,EAAE;wBACX,CAAC,EAAE,KAAK,CAAC,OAAO;wBAChB,CAAC,EAAE,KAAK,CAAC,OAAO;qBACjB;iBACF,CAAC,CAAC;aACJ;QACH,CAAC;KACF;IAED,OAAO,gBAAkD,CAAC;AAC5D,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement } from 'lit';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Interface for components that support ripple effect\n */\nexport interface RippleCapable {\n /**\n * Whether ripple effect is enabled\n */\n ripple: boolean;\n \n /**\n * Whether the component is disabled (affects ripple)\n */\n disabled: boolean;\n \n /**\n * Create ripple effect at click position\n */\n createRipple(event: MouseEvent): void;\n \n /**\n * Handle click events with ripple effect\n */\n handleRippleClick(event: MouseEvent): void;\n}\n\n/**\n * Mixin that provides ripple effect functionality for button-like components\n * \n * @param superClass - The base class to extend\n * @returns Enhanced class with ripple effect capabilities\n * \n * @example\n * ```typescript\n * export class MyButton extends RippleMixin(LitElement) {\n * @property({ type: Boolean }) ripple = true;\n * @property({ type: Boolean }) disabled = false;\n * \n * render() {\n * return html`\n * <button @click=\"${this.handleRippleClick}\">\n * <slot></slot>\n * </button>\n * `;\n * }\n * }\n * ```\n */\nexport const RippleMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class RippleMixinClass extends superClass implements RippleCapable {\n \n declare ripple: boolean;\n declare disabled: boolean;\n \n /**\n * Creates ripple effect on button click\n * @param event - The click event\n */\n createRipple(event: MouseEvent): void {\n if (!this.ripple || this.disabled) return;\n\n const button = event.currentTarget as HTMLElement;\n const rect = button.getBoundingClientRect();\n const size = Math.max(rect.width, rect.height);\n const x = event.clientX - rect.left - size / 2;\n const y = event.clientY - rect.top - size / 2;\n\n const ripple = document.createElement('span');\n ripple.className = 'ripple';\n ripple.style.width = ripple.style.height = size + 'px';\n ripple.style.left = x + 'px';\n ripple.style.top = y + 'px';\n\n // Remove any existing ripples\n const existingRipples = button.querySelectorAll('.ripple');\n existingRipples.forEach(r => r.remove());\n\n button.appendChild(ripple);\n\n // Remove ripple after animation\n setTimeout(() => {\n ripple.remove();\n }, 600);\n }\n\n /**\n * Handle click events with ripple effect and dispatch custom event\n * @param event - The click event\n */\n handleRippleClick(event: MouseEvent): void {\n this.createRipple(event);\n \n // Dispatch custom button click event if EventHandling mixin is available\n if (typeof (this as any).dispatchCustomEvent === 'function') {\n (this as any).dispatchCustomEvent('button-click', {\n disabled: this.disabled,\n timestamp: Date.now(),\n coordinates: {\n x: event.clientX,\n y: event.clientY\n }\n });\n }\n }\n }\n\n return RippleMixinClass as Constructor<RippleCapable> & T;\n};\n"]}
|