@nuralyui/icon 0.0.5 → 0.0.7
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/demo/hy-icon-demo.d.ts +6 -0
- package/demo/hy-icon-demo.d.ts.map +1 -1
- package/demo/hy-icon-demo.js +200 -20
- package/demo/hy-icon-demo.js.map +1 -1
- package/icon.component.d.ts +38 -14
- package/icon.component.d.ts.map +1 -1
- package/icon.component.js +105 -5
- package/icon.component.js.map +1 -1
- package/icon.style.d.ts.map +1 -1
- package/icon.style.js +68 -3
- package/icon.style.js.map +1 -1
- package/icon.variables.d.ts +9 -0
- package/icon.variables.d.ts.map +1 -1
- package/icon.variables.js +72 -5
- package/icon.variables.js.map +1 -1
- package/mixins/clickable-mixin.d.ts +57 -0
- package/mixins/clickable-mixin.d.ts.map +1 -0
- package/mixins/clickable-mixin.js +111 -0
- package/mixins/clickable-mixin.js.map +1 -0
- package/mixins/index.d.ts +7 -0
- package/mixins/index.d.ts.map +1 -0
- package/mixins/index.js +7 -0
- package/mixins/index.js.map +1 -0
- package/package.json +1 -1
package/demo/hy-icon-demo.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
+
import '../icon.component.js';
|
|
2
3
|
export declare class HyIconDemo extends LitElement {
|
|
4
|
+
private currentTheme;
|
|
3
5
|
static readonly styles: import("lit").CSSResult;
|
|
6
|
+
private handleIconClick;
|
|
7
|
+
private logEvent;
|
|
8
|
+
private toggleTheme;
|
|
9
|
+
private clearLog;
|
|
4
10
|
render(): import("lit").TemplateResult<1>;
|
|
5
11
|
}
|
|
6
12
|
declare global {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hy-icon-demo.d.ts","sourceRoot":"","sources":["../../../../src/components/icon/demo/hy-icon-demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAY,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"hy-icon-demo.d.ts","sourceRoot":"","sources":["../../../../src/components/icon/demo/hy-icon-demo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAY,MAAM,KAAK,CAAC;AAE1C,OAAO,sBAAsB,CAAC;AAE9B,qBACa,UAAW,SAAQ,UAAU;IAExC,OAAO,CAAC,YAAY,CAA6B;IAEjD,gBAAyB,MAAM,0BAmG7B;IAEF,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,QAAQ;IAOP,MAAM;CA2EhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,UAAU,CAAC;KAC5B;CACF"}
|
package/demo/hy-icon-demo.js
CHANGED
|
@@ -5,37 +5,217 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { LitElement, css, html } from 'lit';
|
|
8
|
-
import { customElement } from 'lit/decorators.js';
|
|
8
|
+
import { customElement, state } from 'lit/decorators.js';
|
|
9
|
+
import '../icon.component.js';
|
|
9
10
|
let HyIconDemo = class HyIconDemo extends LitElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.currentTheme = 'light';
|
|
14
|
+
}
|
|
15
|
+
handleIconClick(event) {
|
|
16
|
+
const detail = event.detail;
|
|
17
|
+
this.logEvent('icon-click', detail);
|
|
18
|
+
}
|
|
19
|
+
logEvent(eventType, detail) {
|
|
20
|
+
var _a;
|
|
21
|
+
const eventLog = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.event-log');
|
|
22
|
+
if (eventLog) {
|
|
23
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
24
|
+
const logEntry = `[${timestamp}] ${eventType}: ${JSON.stringify(detail)}\n`;
|
|
25
|
+
eventLog.textContent = logEntry + (eventLog.textContent || '');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
toggleTheme() {
|
|
29
|
+
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
|
|
30
|
+
// Apply theme to document for global effect
|
|
31
|
+
document.documentElement.setAttribute('data-theme', this.currentTheme);
|
|
32
|
+
}
|
|
33
|
+
clearLog() {
|
|
34
|
+
var _a;
|
|
35
|
+
const eventLog = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.event-log');
|
|
36
|
+
if (eventLog) {
|
|
37
|
+
eventLog.textContent = '';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
10
40
|
render() {
|
|
11
41
|
return html `
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
42
|
+
<div class="theme-controls" data-theme="${this.currentTheme}">
|
|
43
|
+
<h2>Icon Component Demo - Theme: ${this.currentTheme}</h2>
|
|
44
|
+
<button @click="${this.toggleTheme}" data-theme="${this.currentTheme}">
|
|
45
|
+
Switch to ${this.currentTheme === 'light' ? 'Dark' : 'Light'} Theme
|
|
46
|
+
</button>
|
|
47
|
+
<button @click="${this.clearLog}" data-theme="${this.currentTheme}">
|
|
48
|
+
Clear Event Log
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div class="demo-container" data-theme="${this.currentTheme}">
|
|
53
|
+
<h3>Basic Icons</h3>
|
|
54
|
+
|
|
55
|
+
<div class="icon-group" data-theme="${this.currentTheme}">
|
|
56
|
+
<span>Default solid:</span>
|
|
57
|
+
<hy-icon name="envelope"></hy-icon>
|
|
58
|
+
<span>Regular:</span>
|
|
59
|
+
<hy-icon name="envelope" type="regular"></hy-icon>
|
|
60
|
+
<span>Different icons:</span>
|
|
61
|
+
<hy-icon name="check"></hy-icon>
|
|
62
|
+
<hy-icon name="warning"></hy-icon>
|
|
63
|
+
<hy-icon name="bug"></hy-icon>
|
|
64
|
+
<hy-icon name="heart"></hy-icon>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<h3>Custom Styling</h3>
|
|
68
|
+
|
|
69
|
+
<div class="icon-group" data-theme="${this.currentTheme}">
|
|
70
|
+
<span>Custom red color:</span>
|
|
71
|
+
<hy-icon id="custom-red-icon" name="exclamation-triangle"></hy-icon>
|
|
72
|
+
<span>Custom size:</span>
|
|
73
|
+
<hy-icon id="custom-size-icon" name="star"></hy-icon>
|
|
74
|
+
<span>Custom size + color:</span>
|
|
75
|
+
<hy-icon id="custom-both-icon" name="check-circle"></hy-icon>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<h3>Interactive Icons</h3>
|
|
79
|
+
|
|
80
|
+
<div class="interactive-examples">
|
|
81
|
+
<span>Clickable icons:</span>
|
|
82
|
+
<hy-icon
|
|
83
|
+
name="thumbs-up"
|
|
84
|
+
clickable
|
|
85
|
+
alt="Like button"
|
|
86
|
+
@icon-click="${this.handleIconClick}">
|
|
87
|
+
</hy-icon>
|
|
88
|
+
<hy-icon
|
|
89
|
+
name="heart"
|
|
90
|
+
clickable
|
|
91
|
+
alt="Favorite button"
|
|
92
|
+
@icon-click="${this.handleIconClick}">
|
|
93
|
+
</hy-icon>
|
|
94
|
+
<hy-icon
|
|
95
|
+
name="share"
|
|
96
|
+
clickable
|
|
97
|
+
alt="Share button"
|
|
98
|
+
@icon-click="${this.handleIconClick}">
|
|
99
|
+
</hy-icon>
|
|
100
|
+
<hy-icon
|
|
101
|
+
name="bookmark"
|
|
102
|
+
clickable
|
|
103
|
+
disabled
|
|
104
|
+
alt="Disabled bookmark button"
|
|
105
|
+
@icon-click="${this.handleIconClick}">
|
|
106
|
+
</hy-icon>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<div class="event-log" data-theme="${this.currentTheme}">
|
|
110
|
+
Event log (click icons above to see events)...
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
22
113
|
`;
|
|
23
114
|
}
|
|
24
115
|
};
|
|
25
116
|
HyIconDemo.styles = css `
|
|
26
|
-
|
|
27
|
-
|
|
117
|
+
:host {
|
|
118
|
+
display: block;
|
|
119
|
+
padding: 20px;
|
|
120
|
+
font-family: system-ui, sans-serif;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.demo-container {
|
|
124
|
+
border: 1px solid #e0e0e0;
|
|
125
|
+
padding: 20px;
|
|
126
|
+
border-radius: 8px;
|
|
127
|
+
margin-bottom: 20px;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.demo-container[data-theme="dark"] {
|
|
131
|
+
background: #1a1a1a;
|
|
132
|
+
border-color: #404040;
|
|
133
|
+
color: #ffffff;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.theme-controls {
|
|
137
|
+
margin-bottom: 30px;
|
|
138
|
+
padding: 15px;
|
|
139
|
+
background: #f5f5f5;
|
|
140
|
+
border-radius: 8px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.theme-controls[data-theme="dark"] {
|
|
144
|
+
background: #2d2d2d;
|
|
145
|
+
color: #ffffff;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.icon-group {
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
gap: 15px;
|
|
152
|
+
margin: 15px 0;
|
|
153
|
+
padding: 10px;
|
|
154
|
+
border: 1px dashed #ccc;
|
|
155
|
+
border-radius: 4px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.icon-group[data-theme="dark"] {
|
|
159
|
+
border-color: #555;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#custom-red-icon {
|
|
163
|
+
--hybrid-icon-local-color: #dc3545;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#custom-size-icon {
|
|
167
|
+
--hybrid-icon-local-width: 32px;
|
|
168
|
+
--hybrid-icon-local-height: 32px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#custom-both-icon {
|
|
172
|
+
--hybrid-icon-local-width: 24px;
|
|
173
|
+
--hybrid-icon-local-height: 24px;
|
|
174
|
+
--hybrid-icon-local-color: #28a745;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.interactive-examples {
|
|
178
|
+
display: flex;
|
|
179
|
+
gap: 10px;
|
|
180
|
+
flex-wrap: wrap;
|
|
181
|
+
align-items: center;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
button {
|
|
185
|
+
padding: 8px 16px;
|
|
186
|
+
border: 1px solid #ddd;
|
|
187
|
+
background: #fff;
|
|
188
|
+
border-radius: 4px;
|
|
189
|
+
cursor: pointer;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
button[data-theme="dark"] {
|
|
193
|
+
background: #333;
|
|
194
|
+
border-color: #555;
|
|
195
|
+
color: #fff;
|
|
28
196
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
197
|
+
|
|
198
|
+
.event-log {
|
|
199
|
+
background: #f8f9fa;
|
|
200
|
+
border: 1px solid #dee2e6;
|
|
201
|
+
border-radius: 4px;
|
|
202
|
+
padding: 10px;
|
|
203
|
+
font-family: monospace;
|
|
204
|
+
font-size: 12px;
|
|
205
|
+
max-height: 150px;
|
|
206
|
+
overflow-y: auto;
|
|
207
|
+
margin-top: 15px;
|
|
32
208
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
209
|
+
|
|
210
|
+
.event-log[data-theme="dark"] {
|
|
211
|
+
background: #1e1e1e;
|
|
212
|
+
border-color: #404040;
|
|
213
|
+
color: #ffffff;
|
|
37
214
|
}
|
|
38
215
|
`;
|
|
216
|
+
__decorate([
|
|
217
|
+
state()
|
|
218
|
+
], HyIconDemo.prototype, "currentTheme", void 0);
|
|
39
219
|
HyIconDemo = __decorate([
|
|
40
220
|
customElement('hy-icon-demo')
|
|
41
221
|
], HyIconDemo);
|
package/demo/hy-icon-demo.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hy-icon-demo.js","sourceRoot":"","sources":["../../../../src/components/icon/demo/hy-icon-demo.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAC,UAAU,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAC,aAAa,EAAC,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"hy-icon-demo.js","sourceRoot":"","sources":["../../../../src/components/icon/demo/hy-icon-demo.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAC,UAAU,EAAE,GAAG,EAAE,IAAI,EAAC,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAC,aAAa,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACvD,OAAO,sBAAsB,CAAC;AAG9B,IAAa,UAAU,GAAvB,MAAa,UAAW,SAAQ,UAAU;IAA1C;;QAEU,iBAAY,GAAqB,OAAO,CAAC;IA6MnD,CAAC;IAtGS,eAAe,CAAC,KAAkB;QACxC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAEO,QAAQ,CAAC,SAAiB,EAAE,MAAW;;QAC7C,MAAM,QAAQ,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE;YACZ,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC;YAClD,MAAM,QAAQ,GAAG,IAAI,SAAS,KAAK,SAAS,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;YAC5E,QAAQ,CAAC,WAAW,GAAG,QAAQ,GAAG,CAAC,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;SAChE;IACH,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QACrE,4CAA4C;QAC5C,QAAQ,CAAC,eAAe,CAAC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACzE,CAAC;IAEO,QAAQ;;QACd,MAAM,QAAQ,GAAG,MAAA,IAAI,CAAC,UAAU,0CAAE,aAAa,CAAC,YAAY,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE;YACZ,QAAQ,CAAC,WAAW,GAAG,EAAE,CAAC;SAC3B;IACH,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;gDACiC,IAAI,CAAC,YAAY;2CACtB,IAAI,CAAC,YAAY;0BAClC,IAAI,CAAC,WAAW,iBAAiB,IAAI,CAAC,YAAY;sBACtD,IAAI,CAAC,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;;0BAE5C,IAAI,CAAC,QAAQ,iBAAiB,IAAI,CAAC,YAAY;;;;;gDAKzB,IAAI,CAAC,YAAY;;;8CAGnB,IAAI,CAAC,YAAY;;;;;;;;;;;;;;8CAcjB,IAAI,CAAC,YAAY;;;;;;;;;;;;;;;;;2BAiBpC,IAAI,CAAC,eAAe;;;;;;2BAMpB,IAAI,CAAC,eAAe;;;;;;2BAMpB,IAAI,CAAC,eAAe;;;;;;;2BAOpB,IAAI,CAAC,eAAe;;;;6CAIF,IAAI,CAAC,YAAY;;;;KAIzD,CAAC;IACJ,CAAC;CACF,CAAA;AA3M0B,iBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmGnC,CAAA;AArGF;IADC,KAAK,EAAE;gDACyC;AAFtC,UAAU;IADtB,aAAa,CAAC,cAAc,CAAC;GACjB,UAAU,CA+MtB;SA/MY,UAAU","sourcesContent":["import {LitElement, css, html} from 'lit';\nimport {customElement, state} from 'lit/decorators.js';\nimport '../icon.component.js';\n\n@customElement('hy-icon-demo')\nexport class HyIconDemo extends LitElement {\n @state() \n private currentTheme: 'light' | 'dark' = 'light';\n\n static override readonly styles = css`\n :host {\n display: block;\n padding: 20px;\n font-family: system-ui, sans-serif;\n }\n\n .demo-container {\n border: 1px solid #e0e0e0;\n padding: 20px;\n border-radius: 8px;\n margin-bottom: 20px;\n }\n\n .demo-container[data-theme=\"dark\"] {\n background: #1a1a1a;\n border-color: #404040;\n color: #ffffff;\n }\n\n .theme-controls {\n margin-bottom: 30px;\n padding: 15px;\n background: #f5f5f5;\n border-radius: 8px;\n }\n\n .theme-controls[data-theme=\"dark\"] {\n background: #2d2d2d;\n color: #ffffff;\n }\n\n .icon-group {\n display: flex;\n align-items: center;\n gap: 15px;\n margin: 15px 0;\n padding: 10px;\n border: 1px dashed #ccc;\n border-radius: 4px;\n }\n\n .icon-group[data-theme=\"dark\"] {\n border-color: #555;\n }\n\n #custom-red-icon {\n --hybrid-icon-local-color: #dc3545;\n }\n\n #custom-size-icon {\n --hybrid-icon-local-width: 32px;\n --hybrid-icon-local-height: 32px;\n }\n\n #custom-both-icon {\n --hybrid-icon-local-width: 24px;\n --hybrid-icon-local-height: 24px;\n --hybrid-icon-local-color: #28a745;\n }\n\n .interactive-examples {\n display: flex;\n gap: 10px;\n flex-wrap: wrap;\n align-items: center;\n }\n\n button {\n padding: 8px 16px;\n border: 1px solid #ddd;\n background: #fff;\n border-radius: 4px;\n cursor: pointer;\n }\n\n button[data-theme=\"dark\"] {\n background: #333;\n border-color: #555;\n color: #fff;\n }\n\n .event-log {\n background: #f8f9fa;\n border: 1px solid #dee2e6;\n border-radius: 4px;\n padding: 10px;\n font-family: monospace;\n font-size: 12px;\n max-height: 150px;\n overflow-y: auto;\n margin-top: 15px;\n }\n\n .event-log[data-theme=\"dark\"] {\n background: #1e1e1e;\n border-color: #404040;\n color: #ffffff;\n }\n `;\n\n private handleIconClick(event: CustomEvent) {\n const detail = event.detail;\n this.logEvent('icon-click', detail);\n }\n\n private logEvent(eventType: string, detail: any) {\n const eventLog = this.shadowRoot?.querySelector('.event-log');\n if (eventLog) {\n const timestamp = new Date().toLocaleTimeString();\n const logEntry = `[${timestamp}] ${eventType}: ${JSON.stringify(detail)}\\n`;\n eventLog.textContent = logEntry + (eventLog.textContent || '');\n }\n }\n\n private toggleTheme() {\n this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';\n // Apply theme to document for global effect\n document.documentElement.setAttribute('data-theme', this.currentTheme);\n }\n\n private clearLog() {\n const eventLog = this.shadowRoot?.querySelector('.event-log');\n if (eventLog) {\n eventLog.textContent = '';\n }\n }\n\n override render() {\n return html`\n <div class=\"theme-controls\" data-theme=\"${this.currentTheme}\">\n <h2>Icon Component Demo - Theme: ${this.currentTheme}</h2>\n <button @click=\"${this.toggleTheme}\" data-theme=\"${this.currentTheme}\">\n Switch to ${this.currentTheme === 'light' ? 'Dark' : 'Light'} Theme\n </button>\n <button @click=\"${this.clearLog}\" data-theme=\"${this.currentTheme}\">\n Clear Event Log\n </button>\n </div>\n\n <div class=\"demo-container\" data-theme=\"${this.currentTheme}\">\n <h3>Basic Icons</h3>\n \n <div class=\"icon-group\" data-theme=\"${this.currentTheme}\">\n <span>Default solid:</span>\n <hy-icon name=\"envelope\"></hy-icon>\n <span>Regular:</span>\n <hy-icon name=\"envelope\" type=\"regular\"></hy-icon>\n <span>Different icons:</span>\n <hy-icon name=\"check\"></hy-icon>\n <hy-icon name=\"warning\"></hy-icon>\n <hy-icon name=\"bug\"></hy-icon>\n <hy-icon name=\"heart\"></hy-icon>\n </div>\n\n <h3>Custom Styling</h3>\n \n <div class=\"icon-group\" data-theme=\"${this.currentTheme}\">\n <span>Custom red color:</span>\n <hy-icon id=\"custom-red-icon\" name=\"exclamation-triangle\"></hy-icon>\n <span>Custom size:</span>\n <hy-icon id=\"custom-size-icon\" name=\"star\"></hy-icon>\n <span>Custom size + color:</span>\n <hy-icon id=\"custom-both-icon\" name=\"check-circle\"></hy-icon>\n </div>\n\n <h3>Interactive Icons</h3>\n \n <div class=\"interactive-examples\">\n <span>Clickable icons:</span>\n <hy-icon \n name=\"thumbs-up\" \n clickable \n alt=\"Like button\"\n @icon-click=\"${this.handleIconClick}\">\n </hy-icon>\n <hy-icon \n name=\"heart\" \n clickable \n alt=\"Favorite button\"\n @icon-click=\"${this.handleIconClick}\">\n </hy-icon>\n <hy-icon \n name=\"share\" \n clickable \n alt=\"Share button\"\n @icon-click=\"${this.handleIconClick}\">\n </hy-icon>\n <hy-icon \n name=\"bookmark\" \n clickable \n disabled\n alt=\"Disabled bookmark button\"\n @icon-click=\"${this.handleIconClick}\">\n </hy-icon>\n </div>\n\n <div class=\"event-log\" data-theme=\"${this.currentTheme}\">\n Event log (click icons above to see events)...\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hy-icon-demo': HyIconDemo;\n }\n}\n"]}
|
package/icon.component.d.ts
CHANGED
|
@@ -3,24 +3,48 @@
|
|
|
3
3
|
* Copyright 2023 Nuraly Laabidi Aymen
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
|
-
/// <reference types="react" />
|
|
7
6
|
import { LitElement } from 'lit';
|
|
8
7
|
import { IconTypes } from './icon.types.js';
|
|
9
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Enhanced Icon component with clickable functionality and proper event handling
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```html
|
|
13
|
+
* <hy-icon name="envelope"></hy-icon>
|
|
14
|
+
* <hy-icon name="check" clickable @icon-click="${this.handleIconClick}"></hy-icon>
|
|
15
|
+
* <hy-icon name="warning" type="regular" disabled></hy-icon>
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @fires icon-click - Dispatched when icon is clicked (contains iconName, iconType, originalEvent, timestamp)
|
|
19
|
+
* @fires icon-keyboard-activation - Dispatched when icon is activated via keyboard (contains iconName, iconType, key, originalEvent, timestamp)
|
|
20
|
+
*/
|
|
21
|
+
declare const IconBaseMixin: (new (...args: any[]) => import("./mixins/clickable-mixin.js").ClickableCapable) & (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;
|
|
22
|
+
export declare class HyIconElement extends IconBaseMixin {
|
|
23
|
+
static readonly styles: import("lit").CSSResult[];
|
|
24
|
+
/** The FontAwesome icon name */
|
|
10
25
|
name: string;
|
|
26
|
+
/** The icon type (solid or regular) */
|
|
11
27
|
type: IconTypes;
|
|
12
|
-
|
|
28
|
+
/** Alternative text for accessibility */
|
|
29
|
+
alt: string;
|
|
30
|
+
/**
|
|
31
|
+
* Validate component properties on update
|
|
32
|
+
*/
|
|
33
|
+
willUpdate(changedProperties: Map<string, any>): void;
|
|
13
34
|
render(): import("lit").TemplateResult<1>;
|
|
14
|
-
getIconPath():
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
getIconPath(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Get the appropriate ARIA role for the icon
|
|
38
|
+
*/
|
|
39
|
+
getIconRole(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Get the appropriate tabindex for the icon
|
|
42
|
+
*/
|
|
43
|
+
getIconTabIndex(): string;
|
|
44
|
+
/**
|
|
45
|
+
* Get the appropriate aria-disabled value
|
|
46
|
+
*/
|
|
47
|
+
getAriaDisabled(): string | undefined;
|
|
25
48
|
}
|
|
49
|
+
export {};
|
|
26
50
|
//# sourceMappingURL=icon.component.d.ts.map
|
package/icon.component.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.component.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.component.ts"],"names":[],"mappings":"AACA;;;;GAIG
|
|
1
|
+
{"version":3,"file":"icon.component.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.component.ts"],"names":[],"mappings":"AACA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAQ,MAAM,KAAK,CAAC;AASvC,OAAO,EAAE,SAAS,EAAkC,MAAM,iBAAiB,CAAC;AAI5E;;;;;;;;;;;;GAYG;AAEH,QAAA,MAAM,aAAa,wWAAgD,CAAC;AACpE,qBACa,aAAc,SAAQ,aAAa;IAC9C,gBAAyB,MAAM,4BAAU;IAEzC,gCAAgC;IAEhC,IAAI,EAAG,MAAM,CAAC;IAEd,uCAAuC;IAEvC,IAAI,YAAmB;IAEvB,yCAAyC;IAEzC,GAAG,SAAM;IAET;;OAEG;IACM,UAAU,CAAC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC;IAa9C,MAAM;IAuBf,WAAW;IAmCX;;OAEG;IACM,WAAW,IAAI,MAAM;IAO9B;;OAEG;IACM,eAAe,IAAI,MAAM;IAOlC;;OAEG;IACM,eAAe,IAAI,MAAM,GAAG,SAAS;CAG/C"}
|
package/icon.component.js
CHANGED
|
@@ -19,22 +19,119 @@ library.add(fas, far);
|
|
|
19
19
|
dom.watch();
|
|
20
20
|
import { styles } from './icon.style.js';
|
|
21
21
|
import { regularIconPack, solidIconPack } from './icon.types.js';
|
|
22
|
-
|
|
22
|
+
import { NuralyUIBaseMixin } from '../../shared/base-mixin.js';
|
|
23
|
+
import { ClickableMixin } from './mixins/index.js';
|
|
24
|
+
/**
|
|
25
|
+
* Enhanced Icon component with clickable functionality and proper event handling
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```html
|
|
29
|
+
* <hy-icon name="envelope"></hy-icon>
|
|
30
|
+
* <hy-icon name="check" clickable @icon-click="${this.handleIconClick}"></hy-icon>
|
|
31
|
+
* <hy-icon name="warning" type="regular" disabled></hy-icon>
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @fires icon-click - Dispatched when icon is clicked (contains iconName, iconType, originalEvent, timestamp)
|
|
35
|
+
* @fires icon-keyboard-activation - Dispatched when icon is activated via keyboard (contains iconName, iconType, key, originalEvent, timestamp)
|
|
36
|
+
*/
|
|
37
|
+
const IconBaseMixin = ClickableMixin(NuralyUIBaseMixin(LitElement));
|
|
38
|
+
let HyIconElement = class HyIconElement extends IconBaseMixin {
|
|
23
39
|
constructor() {
|
|
24
40
|
super(...arguments);
|
|
41
|
+
/** The icon type (solid or regular) */
|
|
25
42
|
this.type = "solid" /* IconTypes.Solid */;
|
|
43
|
+
/** Alternative text for accessibility */
|
|
44
|
+
this.alt = '';
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Validate component properties on update
|
|
48
|
+
*/
|
|
49
|
+
willUpdate(changedProperties) {
|
|
50
|
+
super.willUpdate(changedProperties);
|
|
51
|
+
if (changedProperties.has('name') && !this.name) {
|
|
52
|
+
console.error('HyIconElement: "name" property is required');
|
|
53
|
+
}
|
|
54
|
+
if (changedProperties.has('type') &&
|
|
55
|
+
this.type !== "solid" /* IconTypes.Solid */ && this.type !== "regular" /* IconTypes.Regular */) {
|
|
56
|
+
console.warn(`HyIconElement: Invalid type "${this.type}". Using default "${"solid" /* IconTypes.Solid */}"`);
|
|
57
|
+
this.type = "solid" /* IconTypes.Solid */;
|
|
58
|
+
}
|
|
26
59
|
}
|
|
27
60
|
render() {
|
|
61
|
+
const iconPath = this.getIconPath();
|
|
62
|
+
const role = this.getIconRole();
|
|
63
|
+
const tabIndex = this.getIconTabIndex();
|
|
64
|
+
const ariaDisabled = this.getAriaDisabled();
|
|
28
65
|
return html `
|
|
29
|
-
<svg
|
|
30
|
-
|
|
66
|
+
<svg
|
|
67
|
+
class="svg-icon ${this.clickable ? 'clickable' : ''} ${this.disabled ? 'disabled' : ''}"
|
|
68
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
69
|
+
viewBox="0 0 550 550"
|
|
70
|
+
role="${role}"
|
|
71
|
+
tabindex="${tabIndex}"
|
|
72
|
+
aria-label="${this.alt || this.name}"
|
|
73
|
+
aria-disabled="${ariaDisabled || 'false'}"
|
|
74
|
+
data-theme="${this.currentTheme}"
|
|
75
|
+
@click="${this.clickable ? this.handleIconClick : undefined}"
|
|
76
|
+
@keydown="${this.clickable ? this.handleIconKeydown : undefined}"
|
|
77
|
+
>
|
|
78
|
+
<path d="${iconPath}" />
|
|
31
79
|
</svg>
|
|
32
80
|
`;
|
|
33
81
|
}
|
|
34
82
|
getIconPath() {
|
|
83
|
+
if (!this.name) {
|
|
84
|
+
console.warn('HyIconElement: Icon name is required');
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
35
87
|
const iconPack = this.type == "solid" /* IconTypes.Solid */ ? solidIconPack : regularIconPack;
|
|
36
|
-
|
|
37
|
-
|
|
88
|
+
try {
|
|
89
|
+
const definitions = library.definitions;
|
|
90
|
+
if (!definitions || !definitions[iconPack]) {
|
|
91
|
+
console.warn(`HyIconElement: Icon pack "${iconPack}" not found`);
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
const iconDefinition = definitions[iconPack][this.name];
|
|
95
|
+
if (!iconDefinition) {
|
|
96
|
+
console.warn(`HyIconElement: Icon "${this.name}" not found in ${iconPack} pack`);
|
|
97
|
+
return '';
|
|
98
|
+
}
|
|
99
|
+
// Validate that the path data exists
|
|
100
|
+
const pathData = iconDefinition[4];
|
|
101
|
+
if (!pathData || typeof pathData !== 'string') {
|
|
102
|
+
console.warn(`HyIconElement: Invalid path data for icon "${this.name}"`);
|
|
103
|
+
return '';
|
|
104
|
+
}
|
|
105
|
+
return pathData;
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error(`HyIconElement: Error loading icon "${this.name}":`, error);
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get the appropriate ARIA role for the icon
|
|
114
|
+
*/
|
|
115
|
+
getIconRole() {
|
|
116
|
+
if (this.clickable) {
|
|
117
|
+
return 'button';
|
|
118
|
+
}
|
|
119
|
+
return this.alt ? 'img' : 'presentation';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the appropriate tabindex for the icon
|
|
123
|
+
*/
|
|
124
|
+
getIconTabIndex() {
|
|
125
|
+
if (this.clickable && !this.disabled) {
|
|
126
|
+
return '0';
|
|
127
|
+
}
|
|
128
|
+
return '-1';
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the appropriate aria-disabled value
|
|
132
|
+
*/
|
|
133
|
+
getAriaDisabled() {
|
|
134
|
+
return this.disabled ? 'true' : undefined;
|
|
38
135
|
}
|
|
39
136
|
};
|
|
40
137
|
HyIconElement.styles = styles;
|
|
@@ -44,6 +141,9 @@ __decorate([
|
|
|
44
141
|
__decorate([
|
|
45
142
|
property()
|
|
46
143
|
], HyIconElement.prototype, "type", void 0);
|
|
144
|
+
__decorate([
|
|
145
|
+
property({ type: String, attribute: 'alt' })
|
|
146
|
+
], HyIconElement.prototype, "alt", void 0);
|
|
47
147
|
HyIconElement = __decorate([
|
|
48
148
|
customElement('hy-icon')
|
|
49
149
|
], HyIconElement);
|
package/icon.component.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.component.js","sourceRoot":"","sources":["../../../src/components/icon/icon.component.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD;;;;GAIG;;;;;;;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"icon.component.js","sourceRoot":"","sources":["../../../src/components/icon/icon.component.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * @license\n * Copyright 2023 Nuraly Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement, html } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { library, dom } from '@fortawesome/fontawesome-svg-core';\nimport { far } from '@fortawesome/free-regular-svg-icons';\nimport { fas } from '@fortawesome/free-solid-svg-icons';\nlibrary.add(fas, far);\ndom.watch();\n\nimport { styles } from './icon.style.js';\nimport { IconTypes, regularIconPack, solidIconPack } from './icon.types.js';\nimport { NuralyUIBaseMixin } from '../../shared/base-mixin.js';\nimport { ClickableMixin } from './mixins/index.js';\n\n/**\n * Enhanced Icon component with clickable functionality and proper event handling\n * \n * @example\n * ```html\n * <hy-icon name=\"envelope\"></hy-icon>\n * <hy-icon name=\"check\" clickable @icon-click=\"${this.handleIconClick}\"></hy-icon>\n * <hy-icon name=\"warning\" type=\"regular\" disabled></hy-icon>\n * ```\n * \n * @fires icon-click - Dispatched when icon is clicked (contains iconName, iconType, originalEvent, timestamp)\n * @fires icon-keyboard-activation - Dispatched when icon is activated via keyboard (contains iconName, iconType, key, originalEvent, timestamp)\n */\n\nconst IconBaseMixin = ClickableMixin(NuralyUIBaseMixin(LitElement));\n@customElement('hy-icon')\nexport class HyIconElement extends IconBaseMixin {\n static override readonly styles = styles;\n\n /** The FontAwesome icon name */\n @property({type: String})\n name!: string;\n\n /** The icon type (solid or regular) */\n @property()\n type = IconTypes.Solid;\n\n /** Alternative text for accessibility */\n @property({type: String, attribute: 'alt'})\n alt = '';\n\n /**\n * Validate component properties on update\n */\n override willUpdate(changedProperties: Map<string, any>) {\n super.willUpdate(changedProperties);\n \n if (changedProperties.has('name') && !this.name) {\n console.error('HyIconElement: \"name\" property is required');\n }\n \n if (changedProperties.has('type') && \n this.type !== IconTypes.Solid && this.type !== IconTypes.Regular) {\n console.warn(`HyIconElement: Invalid type \"${this.type}\". Using default \"${IconTypes.Solid}\"`);\n this.type = IconTypes.Solid;\n }\n }\n override render() {\n const iconPath = this.getIconPath();\n const role = this.getIconRole();\n const tabIndex = this.getIconTabIndex();\n const ariaDisabled = this.getAriaDisabled();\n \n return html`\n <svg \n class=\"svg-icon ${this.clickable ? 'clickable' : ''} ${this.disabled ? 'disabled' : ''}\"\n xmlns=\"http://www.w3.org/2000/svg\" \n viewBox=\"0 0 550 550\"\n role=\"${role}\"\n tabindex=\"${tabIndex}\"\n aria-label=\"${this.alt || this.name}\"\n aria-disabled=\"${ariaDisabled || 'false'}\"\n data-theme=\"${this.currentTheme}\"\n @click=\"${this.clickable ? this.handleIconClick : undefined}\"\n @keydown=\"${this.clickable ? this.handleIconKeydown : undefined}\"\n >\n <path d=\"${iconPath}\" />\n </svg>\n `;\n }\n getIconPath() {\n if (!this.name) {\n console.warn('HyIconElement: Icon name is required');\n return '';\n }\n\n const iconPack = this.type == IconTypes.Solid ? solidIconPack : regularIconPack;\n \n try {\n const definitions = (library as any).definitions;\n if (!definitions || !definitions[iconPack]) {\n console.warn(`HyIconElement: Icon pack \"${iconPack}\" not found`);\n return '';\n }\n\n const iconDefinition = definitions[iconPack][this.name];\n if (!iconDefinition) {\n console.warn(`HyIconElement: Icon \"${this.name}\" not found in ${iconPack} pack`);\n return '';\n }\n\n // Validate that the path data exists\n const pathData = iconDefinition[4];\n if (!pathData || typeof pathData !== 'string') {\n console.warn(`HyIconElement: Invalid path data for icon \"${this.name}\"`);\n return '';\n }\n\n return pathData;\n } catch (error) {\n console.error(`HyIconElement: Error loading icon \"${this.name}\":`, error);\n return '';\n }\n }\n\n /**\n * Get the appropriate ARIA role for the icon\n */\n override getIconRole(): string {\n if (this.clickable) {\n return 'button';\n }\n return this.alt ? 'img' : 'presentation';\n }\n\n /**\n * Get the appropriate tabindex for the icon\n */\n override getIconTabIndex(): string {\n if (this.clickable && !this.disabled) {\n return '0';\n }\n return '-1';\n }\n\n /**\n * Get the appropriate aria-disabled value\n */\n override getAriaDisabled(): string | undefined {\n return this.disabled ? 'true' : undefined;\n }\n}\n"]}
|
package/icon.style.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.style.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.style.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"icon.style.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.style.ts"],"names":[],"mappings":"AA2EA,eAAO,MAAM,MAAM,2BAA+B,CAAC"}
|
package/icon.style.js
CHANGED
|
@@ -1,10 +1,75 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
2
|
import { styleVariables } from './icon.variables.js';
|
|
3
|
+
/**
|
|
4
|
+
* Icon component styles with theme support and interactive states
|
|
5
|
+
*
|
|
6
|
+
* Uses CSS custom properties for theming with fallbacks for backwards compatibility.
|
|
7
|
+
* Supports both light and dark themes via data-theme attribute.
|
|
8
|
+
*/
|
|
3
9
|
const iconStyles = css `
|
|
10
|
+
:host {
|
|
11
|
+
display: inline-block;
|
|
12
|
+
line-height: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
4
15
|
.svg-icon {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
16
|
+
/* Basic properties */
|
|
17
|
+
fill: var(--hybrid-icon-local-color, var(--hybrid-icon-color, #000000));
|
|
18
|
+
width: var(--hybrid-icon-local-width, var(--hybrid-icon-width, 18px));
|
|
19
|
+
height: var(--hybrid-icon-local-height, var(--hybrid-icon-height, 18px));
|
|
20
|
+
transition: var(--hybrid-icon-local-transition, opacity 0.2s ease, transform 0.2s ease);
|
|
21
|
+
|
|
22
|
+
/* Cursor handling */
|
|
23
|
+
cursor: default;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* ========================================
|
|
27
|
+
* CLICKABLE STATES
|
|
28
|
+
* ======================================== */
|
|
29
|
+
|
|
30
|
+
.svg-icon.clickable {
|
|
31
|
+
cursor: var(--hybrid-icon-local-cursor, pointer);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.svg-icon.clickable:hover {
|
|
35
|
+
opacity: var(--hybrid-icon-local-hover-opacity, 0.8);
|
|
36
|
+
transform: var(--hybrid-icon-local-hover-transform, scale(1.1));
|
|
37
|
+
fill: var(--hybrid-icon-local-hover-color, var(--hybrid-icon-local-color, #0f62fe));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.svg-icon.clickable:active {
|
|
41
|
+
opacity: var(--hybrid-icon-local-active-opacity, 0.6);
|
|
42
|
+
transform: var(--hybrid-icon-local-active-transform, scale(0.95));
|
|
43
|
+
fill: var(--hybrid-icon-local-active-color, var(--hybrid-icon-local-color, #054ada));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.svg-icon.clickable:focus {
|
|
47
|
+
outline: var(--hybrid-icon-local-focus-outline, 2px solid #0f62fe);
|
|
48
|
+
outline-offset: var(--hybrid-icon-local-focus-outline-offset, 2px);
|
|
49
|
+
background: var(--hybrid-icon-local-focus-background, rgba(15, 98, 254, 0.1));
|
|
50
|
+
border-radius: var(--hybrid-icon-local-focus-border-radius, 4px);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* ========================================
|
|
54
|
+
* DISABLED STATE
|
|
55
|
+
* ======================================== */
|
|
56
|
+
|
|
57
|
+
.svg-icon.disabled {
|
|
58
|
+
opacity: var(--hybrid-icon-local-disabled-opacity, 0.4);
|
|
59
|
+
fill: var(--hybrid-icon-local-disabled-color, #c6c6c6);
|
|
60
|
+
cursor: var(--hybrid-icon-local-disabled-cursor, not-allowed);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.svg-icon.clickable.disabled:hover,
|
|
64
|
+
.svg-icon.clickable.disabled:active {
|
|
65
|
+
opacity: var(--hybrid-icon-local-disabled-opacity, 0.4);
|
|
66
|
+
fill: var(--hybrid-icon-local-disabled-color, #c6c6c6);
|
|
67
|
+
transform: none;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.svg-icon.clickable.disabled:focus {
|
|
71
|
+
outline: none;
|
|
72
|
+
background: none;
|
|
8
73
|
}
|
|
9
74
|
`;
|
|
10
75
|
export const styles = [iconStyles, styleVariables];
|
package/icon.style.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.style.js","sourceRoot":"","sources":["../../../src/components/icon/icon.style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAEnD,MAAM,UAAU,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"icon.style.js","sourceRoot":"","sources":["../../../src/components/icon/icon.style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,KAAK,CAAC;AACxB,OAAO,EAAC,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiErB,CAAC;AACF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC","sourcesContent":["import {css} from 'lit';\nimport {styleVariables} from './icon.variables.js';\n\n/**\n * Icon component styles with theme support and interactive states\n * \n * Uses CSS custom properties for theming with fallbacks for backwards compatibility.\n * Supports both light and dark themes via data-theme attribute.\n */\nconst iconStyles = css`\n :host {\n display: inline-block;\n line-height: 0;\n }\n\n .svg-icon {\n /* Basic properties */\n fill: var(--hybrid-icon-local-color, var(--hybrid-icon-color, #000000));\n width: var(--hybrid-icon-local-width, var(--hybrid-icon-width, 18px));\n height: var(--hybrid-icon-local-height, var(--hybrid-icon-height, 18px));\n transition: var(--hybrid-icon-local-transition, opacity 0.2s ease, transform 0.2s ease);\n \n /* Cursor handling */\n cursor: default;\n }\n\n /* ========================================\n * CLICKABLE STATES\n * ======================================== */\n \n .svg-icon.clickable {\n cursor: var(--hybrid-icon-local-cursor, pointer);\n }\n\n .svg-icon.clickable:hover {\n opacity: var(--hybrid-icon-local-hover-opacity, 0.8);\n transform: var(--hybrid-icon-local-hover-transform, scale(1.1));\n fill: var(--hybrid-icon-local-hover-color, var(--hybrid-icon-local-color, #0f62fe));\n }\n\n .svg-icon.clickable:active {\n opacity: var(--hybrid-icon-local-active-opacity, 0.6);\n transform: var(--hybrid-icon-local-active-transform, scale(0.95));\n fill: var(--hybrid-icon-local-active-color, var(--hybrid-icon-local-color, #054ada));\n }\n\n .svg-icon.clickable:focus {\n outline: var(--hybrid-icon-local-focus-outline, 2px solid #0f62fe);\n outline-offset: var(--hybrid-icon-local-focus-outline-offset, 2px);\n background: var(--hybrid-icon-local-focus-background, rgba(15, 98, 254, 0.1));\n border-radius: var(--hybrid-icon-local-focus-border-radius, 4px);\n }\n\n /* ========================================\n * DISABLED STATE\n * ======================================== */\n \n .svg-icon.disabled {\n opacity: var(--hybrid-icon-local-disabled-opacity, 0.4);\n fill: var(--hybrid-icon-local-disabled-color, #c6c6c6);\n cursor: var(--hybrid-icon-local-disabled-cursor, not-allowed);\n }\n\n .svg-icon.clickable.disabled:hover,\n .svg-icon.clickable.disabled:active {\n opacity: var(--hybrid-icon-local-disabled-opacity, 0.4);\n fill: var(--hybrid-icon-local-disabled-color, #c6c6c6);\n transform: none;\n }\n\n .svg-icon.clickable.disabled:focus {\n outline: none;\n background: none;\n }\n`;\nexport const styles = [iconStyles, styleVariables];\n"]}
|
package/icon.variables.d.ts
CHANGED
|
@@ -1,2 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon component CSS custom properties (design tokens)
|
|
3
|
+
*
|
|
4
|
+
* This file contains all the CSS custom properties used by the hy-icon component,
|
|
5
|
+
* organized by functionality and including both light and dark theme variants.
|
|
6
|
+
*
|
|
7
|
+
* The styling system uses CSS custom properties with fallbacks to allow
|
|
8
|
+
* for both global and local customization of icon appearance.
|
|
9
|
+
*/
|
|
1
10
|
export declare const styleVariables: import("lit").CSSResult;
|
|
2
11
|
//# sourceMappingURL=icon.variables.d.ts.map
|
package/icon.variables.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.variables.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.variables.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"icon.variables.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.variables.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,yBAqE1B,CAAC"}
|
package/icon.variables.js
CHANGED
|
@@ -1,13 +1,80 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* Icon component CSS custom properties (design tokens)
|
|
4
|
+
*
|
|
5
|
+
* This file contains all the CSS custom properties used by the hy-icon component,
|
|
6
|
+
* organized by functionality and including both light and dark theme variants.
|
|
7
|
+
*
|
|
8
|
+
* The styling system uses CSS custom properties with fallbacks to allow
|
|
9
|
+
* for both global and local customization of icon appearance.
|
|
10
|
+
*/
|
|
2
11
|
export const styleVariables = css `
|
|
3
12
|
:host {
|
|
4
|
-
/*
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
/* ----------------------------------------
|
|
14
|
+
* BASIC ICON PROPERTIES
|
|
15
|
+
* ---------------------------------------- */
|
|
16
|
+
--hybrid-icon-local-color: #000000;
|
|
17
|
+
--hybrid-icon-local-width: 18px;
|
|
18
|
+
--hybrid-icon-local-height: 18px;
|
|
19
|
+
|
|
20
|
+
/* ----------------------------------------
|
|
21
|
+
* INTERACTIVE STATES
|
|
22
|
+
* ---------------------------------------- */
|
|
23
|
+
--hybrid-icon-local-transition: opacity 0.2s ease, transform 0.2s ease;
|
|
24
|
+
--hybrid-icon-local-hover-opacity: 0.8;
|
|
25
|
+
--hybrid-icon-local-hover-transform: scale(1.1);
|
|
26
|
+
--hybrid-icon-local-hover-color: #0f62fe;
|
|
27
|
+
--hybrid-icon-local-active-opacity: 0.6;
|
|
28
|
+
--hybrid-icon-local-active-transform: scale(0.95);
|
|
29
|
+
--hybrid-icon-local-active-color: #054ada;
|
|
30
|
+
--hybrid-icon-local-disabled-opacity: 0.4;
|
|
31
|
+
--hybrid-icon-local-disabled-color: #c6c6c6;
|
|
32
|
+
|
|
33
|
+
/* ----------------------------------------
|
|
34
|
+
* FOCUS STYLES
|
|
35
|
+
* ---------------------------------------- */
|
|
36
|
+
--hybrid-icon-local-focus-outline: 2px solid #0f62fe;
|
|
37
|
+
--hybrid-icon-local-focus-outline-offset: 2px;
|
|
38
|
+
--hybrid-icon-local-focus-background: rgba(15, 98, 254, 0.1);
|
|
39
|
+
--hybrid-icon-local-focus-border-radius: 4px;
|
|
40
|
+
|
|
41
|
+
/* ----------------------------------------
|
|
42
|
+
* CURSOR STYLES
|
|
43
|
+
* ---------------------------------------- */
|
|
44
|
+
--hybrid-icon-local-cursor: pointer;
|
|
45
|
+
--hybrid-icon-local-disabled-cursor: not-allowed;
|
|
7
46
|
}
|
|
8
|
-
|
|
47
|
+
|
|
48
|
+
/* ========================================
|
|
49
|
+
* DARK THEME OVERRIDES
|
|
50
|
+
* ======================================== */
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Dark theme styles using data-theme attribute on the SVG element
|
|
54
|
+
* These override the light theme defaults when data-theme="dark" is applied
|
|
55
|
+
*/
|
|
56
|
+
.svg-icon[data-theme="dark"] {
|
|
57
|
+
--hybrid-icon-local-color: #ffffff;
|
|
58
|
+
--hybrid-icon-local-hover-color: #78a9ff;
|
|
59
|
+
--hybrid-icon-local-active-color: #a6c8ff;
|
|
60
|
+
--hybrid-icon-local-disabled-color: #6f6f6f;
|
|
61
|
+
--hybrid-icon-local-focus-outline: 2px solid #78a9ff;
|
|
62
|
+
--hybrid-icon-local-focus-background: rgba(120, 169, 255, 0.1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ========================================
|
|
66
|
+
* REDUCED MOTION SUPPORT
|
|
67
|
+
* ======================================== */
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Accessibility: Respect user's motion preferences
|
|
71
|
+
* Disables animations when user prefers reduced motion
|
|
72
|
+
*/
|
|
73
|
+
@media (prefers-reduced-motion: reduce) {
|
|
9
74
|
:host {
|
|
10
|
-
--hybrid-icon-
|
|
75
|
+
--hybrid-icon-local-transition: none;
|
|
76
|
+
--hybrid-icon-local-hover-transform: none;
|
|
77
|
+
--hybrid-icon-local-active-transform: none;
|
|
11
78
|
}
|
|
12
79
|
}
|
|
13
80
|
`;
|
package/icon.variables.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"icon.variables.js","sourceRoot":"","sources":["../../../src/components/icon/icon.variables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAA
|
|
1
|
+
{"version":3,"file":"icon.variables.js","sourceRoot":"","sources":["../../../src/components/icon/icon.variables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqEhC,CAAC","sourcesContent":["import { css } from 'lit';\n\n/**\n * Icon component CSS custom properties (design tokens)\n * \n * This file contains all the CSS custom properties used by the hy-icon component,\n * organized by functionality and including both light and dark theme variants.\n * \n * The styling system uses CSS custom properties with fallbacks to allow\n * for both global and local customization of icon appearance.\n */\nexport const styleVariables = css`\n :host {\n /* ----------------------------------------\n * BASIC ICON PROPERTIES\n * ---------------------------------------- */\n --hybrid-icon-local-color: #000000;\n --hybrid-icon-local-width: 18px;\n --hybrid-icon-local-height: 18px;\n\n /* ----------------------------------------\n * INTERACTIVE STATES\n * ---------------------------------------- */\n --hybrid-icon-local-transition: opacity 0.2s ease, transform 0.2s ease;\n --hybrid-icon-local-hover-opacity: 0.8;\n --hybrid-icon-local-hover-transform: scale(1.1);\n --hybrid-icon-local-hover-color: #0f62fe;\n --hybrid-icon-local-active-opacity: 0.6;\n --hybrid-icon-local-active-transform: scale(0.95);\n --hybrid-icon-local-active-color: #054ada;\n --hybrid-icon-local-disabled-opacity: 0.4;\n --hybrid-icon-local-disabled-color: #c6c6c6;\n \n /* ----------------------------------------\n * FOCUS STYLES\n * ---------------------------------------- */\n --hybrid-icon-local-focus-outline: 2px solid #0f62fe;\n --hybrid-icon-local-focus-outline-offset: 2px;\n --hybrid-icon-local-focus-background: rgba(15, 98, 254, 0.1);\n --hybrid-icon-local-focus-border-radius: 4px;\n\n /* ----------------------------------------\n * CURSOR STYLES\n * ---------------------------------------- */\n --hybrid-icon-local-cursor: pointer;\n --hybrid-icon-local-disabled-cursor: not-allowed;\n }\n\n /* ========================================\n * DARK THEME OVERRIDES\n * ======================================== */\n \n /**\n * Dark theme styles using data-theme attribute on the SVG element\n * These override the light theme defaults when data-theme=\"dark\" is applied\n */\n .svg-icon[data-theme=\"dark\"] {\n --hybrid-icon-local-color: #ffffff;\n --hybrid-icon-local-hover-color: #78a9ff;\n --hybrid-icon-local-active-color: #a6c8ff;\n --hybrid-icon-local-disabled-color: #6f6f6f;\n --hybrid-icon-local-focus-outline: 2px solid #78a9ff;\n --hybrid-icon-local-focus-background: rgba(120, 169, 255, 0.1);\n }\n\n /* ========================================\n * REDUCED MOTION SUPPORT\n * ======================================== */\n \n /**\n * Accessibility: Respect user's motion preferences\n * Disables animations when user prefers reduced motion\n */\n @media (prefers-reduced-motion: reduce) {\n :host {\n --hybrid-icon-local-transition: none;\n --hybrid-icon-local-hover-transform: none;\n --hybrid-icon-local-active-transform: none;\n }\n }\n`;\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
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 clickable icon functionality
|
|
10
|
+
*/
|
|
11
|
+
export interface ClickableCapable {
|
|
12
|
+
/**
|
|
13
|
+
* Whether the icon is clickable/interactive
|
|
14
|
+
*/
|
|
15
|
+
clickable: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the icon is disabled
|
|
18
|
+
*/
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Handle click events on the icon
|
|
22
|
+
*/
|
|
23
|
+
handleIconClick(event: MouseEvent): void;
|
|
24
|
+
/**
|
|
25
|
+
* Handle keyboard events for accessibility
|
|
26
|
+
*/
|
|
27
|
+
handleIconKeydown(event: KeyboardEvent): void;
|
|
28
|
+
/**
|
|
29
|
+
* Get appropriate role for accessibility
|
|
30
|
+
*/
|
|
31
|
+
getIconRole(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Get appropriate tabindex for accessibility
|
|
34
|
+
*/
|
|
35
|
+
getIconTabIndex(): string;
|
|
36
|
+
/**
|
|
37
|
+
* Get appropriate aria-disabled attribute
|
|
38
|
+
*/
|
|
39
|
+
getAriaDisabled(): string | undefined;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Mixin that provides clickable icon functionality with proper event handling
|
|
43
|
+
* and accessibility support.
|
|
44
|
+
*
|
|
45
|
+
* @param superClass - The base class to extend
|
|
46
|
+
* @returns Enhanced class with clickable capabilities
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* export class IconComponent extends ClickableMixin(NuralyUIBaseMixin(LitElement)) {
|
|
51
|
+
* // Component implementation
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare const ClickableMixin: <T extends Constructor<LitElement>>(superClass: T) => Constructor<ClickableCapable> & T;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=clickable-mixin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickable-mixin.d.ts","sourceRoot":"","sources":["../../../../src/components/icon/mixins/clickable-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAGjC,aAAK,WAAW,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEzC;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAE9C;;OAEG;IACH,WAAW,IAAI,MAAM,CAAC;IAEtB;;OAEG;IACH,eAAe,IAAI,MAAM,CAAC;IAE1B;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS,CAAC;CACvC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,yFAwF1B,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2023 Nuraly, Laabidi Aymen
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
7
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
9
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
10
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
11
|
+
};
|
|
12
|
+
import { property } from 'lit/decorators.js';
|
|
13
|
+
/**
|
|
14
|
+
* Mixin that provides clickable icon functionality with proper event handling
|
|
15
|
+
* and accessibility support.
|
|
16
|
+
*
|
|
17
|
+
* @param superClass - The base class to extend
|
|
18
|
+
* @returns Enhanced class with clickable capabilities
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* export class IconComponent extends ClickableMixin(NuralyUIBaseMixin(LitElement)) {
|
|
23
|
+
* // Component implementation
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const ClickableMixin = (superClass) => {
|
|
28
|
+
class ClickableMixinClass extends superClass {
|
|
29
|
+
constructor() {
|
|
30
|
+
super(...arguments);
|
|
31
|
+
/** Whether the icon is clickable/interactive */
|
|
32
|
+
this.clickable = false;
|
|
33
|
+
/** Whether the icon is disabled */
|
|
34
|
+
this.disabled = false;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Handle click events on the icon
|
|
38
|
+
*/
|
|
39
|
+
handleIconClick(event) {
|
|
40
|
+
if (this.disabled || !this.clickable) {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
event.stopPropagation();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Dispatch custom click event with icon details
|
|
46
|
+
this.dispatchCustomEvent('icon-click', {
|
|
47
|
+
iconName: this.name,
|
|
48
|
+
iconType: this.type,
|
|
49
|
+
originalEvent: event,
|
|
50
|
+
timestamp: Date.now()
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Handle keyboard events for accessibility
|
|
55
|
+
*/
|
|
56
|
+
handleIconKeydown(event) {
|
|
57
|
+
if (this.disabled || !this.clickable) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Check if it's an activation key (Enter or Space)
|
|
61
|
+
// Use isActivationKey from EventHandlerMixin if available, otherwise fallback
|
|
62
|
+
const isActivationKey = typeof this.isActivationKey === 'function'
|
|
63
|
+
? this.isActivationKey(event)
|
|
64
|
+
: (event.key === 'Enter' || event.key === ' ');
|
|
65
|
+
if (isActivationKey) {
|
|
66
|
+
event.preventDefault();
|
|
67
|
+
event.stopPropagation();
|
|
68
|
+
// Simulate click event
|
|
69
|
+
this.handleIconClick(event);
|
|
70
|
+
// Dispatch keyboard activation event with improved naming consistency
|
|
71
|
+
if (typeof this.dispatchCustomEvent === 'function') {
|
|
72
|
+
this.dispatchCustomEvent('icon-keyboard-activation', {
|
|
73
|
+
iconName: this.name,
|
|
74
|
+
iconType: this.type,
|
|
75
|
+
key: event.key,
|
|
76
|
+
originalEvent: event,
|
|
77
|
+
timestamp: Date.now()
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get appropriate role for accessibility
|
|
84
|
+
*/
|
|
85
|
+
getIconRole() {
|
|
86
|
+
return this.clickable ? 'button' : 'img';
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get appropriate tabindex for accessibility
|
|
90
|
+
*/
|
|
91
|
+
getIconTabIndex() {
|
|
92
|
+
if (!this.clickable)
|
|
93
|
+
return '-1';
|
|
94
|
+
return this.disabled ? '-1' : '0';
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get appropriate aria-disabled attribute
|
|
98
|
+
*/
|
|
99
|
+
getAriaDisabled() {
|
|
100
|
+
return this.clickable && this.disabled ? 'true' : undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
__decorate([
|
|
104
|
+
property({ type: Boolean, reflect: true })
|
|
105
|
+
], ClickableMixinClass.prototype, "clickable", void 0);
|
|
106
|
+
__decorate([
|
|
107
|
+
property({ type: Boolean, reflect: true })
|
|
108
|
+
], ClickableMixinClass.prototype, "disabled", void 0);
|
|
109
|
+
return ClickableMixinClass;
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=clickable-mixin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clickable-mixin.js","sourceRoot":"","sources":["../../../../src/components/icon/mixins/clickable-mixin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;;;;;;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AA4C7C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAoC,UAAa,EAAE,EAAE;IACjF,MAAM,mBAAoB,SAAQ,UAAU;QAA5C;;YAEE,gDAAgD;YAEhD,cAAS,GAAG,KAAK,CAAC;YAElB,mCAAmC;YAEnC,aAAQ,GAAG,KAAK,CAAC;QA4EnB,CAAC;QA1EC;;WAEG;QACH,eAAe,CAAC,KAAiB;YAC/B,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACpC,KAAK,CAAC,cAAc,EAAE,CAAC;gBACvB,KAAK,CAAC,eAAe,EAAE,CAAC;gBACxB,OAAO;aACR;YAED,gDAAgD;YAC/C,IAAY,CAAC,mBAAmB,CAAC,YAAY,EAAE;gBAC9C,QAAQ,EAAG,IAAY,CAAC,IAAI;gBAC5B,QAAQ,EAAG,IAAY,CAAC,IAAI;gBAC5B,aAAa,EAAE,KAAK;gBACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC;QAED;;WAEG;QACH,iBAAiB,CAAC,KAAoB;YACpC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE;gBACpC,OAAO;aACR;YAED,mDAAmD;YACnD,8EAA8E;YAC9E,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;gBACvB,KAAK,CAAC,eAAe,EAAE,CAAC;gBAExB,uBAAuB;gBACvB,IAAI,CAAC,eAAe,CAAC,KAAY,CAAC,CAAC;gBAEnC,sEAAsE;gBACtE,IAAI,OAAQ,IAAY,CAAC,mBAAmB,KAAK,UAAU,EAAE;oBAC1D,IAAY,CAAC,mBAAmB,CAAC,0BAA0B,EAAE;wBAC5D,QAAQ,EAAG,IAAY,CAAC,IAAI;wBAC5B,QAAQ,EAAG,IAAY,CAAC,IAAI;wBAC5B,GAAG,EAAE,KAAK,CAAC,GAAG;wBACd,aAAa,EAAE,KAAK;wBACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;qBACtB,CAAC,CAAC;iBACJ;aACF;QACH,CAAC;QAED;;WAEG;QACH,WAAW;YACT,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;QAC3C,CAAC;QAED;;WAEG;QACH,eAAe;YACb,IAAI,CAAC,IAAI,CAAC,SAAS;gBAAE,OAAO,IAAI,CAAC;YACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;QACpC,CAAC;QAED;;WAEG;QACH,eAAe;YACb,OAAO,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,CAAC;KACF;IAhFC;QADC,QAAQ,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC;0DACvB;IAIlB;QADC,QAAQ,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAC,CAAC;yDACxB;IA8EnB,OAAO,mBAAwD,CAAC;AAClE,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nimport { LitElement } from 'lit';\nimport { property } from 'lit/decorators.js';\n\ntype Constructor<T = {}> = new (...args: any[]) => T;\n\n/**\n * Interface for components that support clickable icon functionality\n */\nexport interface ClickableCapable {\n /**\n * Whether the icon is clickable/interactive\n */\n clickable: boolean;\n \n /**\n * Whether the icon is disabled\n */\n disabled: boolean;\n \n /**\n * Handle click events on the icon\n */\n handleIconClick(event: MouseEvent): void;\n \n /**\n * Handle keyboard events for accessibility\n */\n handleIconKeydown(event: KeyboardEvent): void;\n \n /**\n * Get appropriate role for accessibility\n */\n getIconRole(): string;\n \n /**\n * Get appropriate tabindex for accessibility\n */\n getIconTabIndex(): string;\n \n /**\n * Get appropriate aria-disabled attribute\n */\n getAriaDisabled(): string | undefined;\n}\n\n/**\n * Mixin that provides clickable icon functionality with proper event handling\n * and accessibility support.\n * \n * @param superClass - The base class to extend\n * @returns Enhanced class with clickable capabilities\n * \n * @example\n * ```typescript\n * export class IconComponent extends ClickableMixin(NuralyUIBaseMixin(LitElement)) {\n * // Component implementation\n * }\n * ```\n */\nexport const ClickableMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class ClickableMixinClass extends superClass implements ClickableCapable {\n \n /** Whether the icon is clickable/interactive */\n @property({type: Boolean, reflect: true})\n clickable = false;\n \n /** Whether the icon is disabled */\n @property({type: Boolean, reflect: true})\n disabled = false;\n\n /**\n * Handle click events on the icon\n */\n handleIconClick(event: MouseEvent): void {\n if (this.disabled || !this.clickable) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n // Dispatch custom click event with icon details\n (this as any).dispatchCustomEvent('icon-click', {\n iconName: (this as any).name,\n iconType: (this as any).type,\n originalEvent: event,\n timestamp: Date.now()\n });\n }\n\n /**\n * Handle keyboard events for accessibility\n */\n handleIconKeydown(event: KeyboardEvent): void {\n if (this.disabled || !this.clickable) {\n return;\n }\n\n // Check if it's an activation key (Enter or Space)\n // Use isActivationKey from EventHandlerMixin if available, otherwise fallback\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 event.stopPropagation();\n \n // Simulate click event\n this.handleIconClick(event as any);\n \n // Dispatch keyboard activation event with improved naming consistency\n if (typeof (this as any).dispatchCustomEvent === 'function') {\n (this as any).dispatchCustomEvent('icon-keyboard-activation', {\n iconName: (this as any).name,\n iconType: (this as any).type,\n key: event.key,\n originalEvent: event,\n timestamp: Date.now()\n });\n }\n }\n }\n\n /**\n * Get appropriate role for accessibility\n */\n getIconRole(): string {\n return this.clickable ? 'button' : 'img';\n }\n\n /**\n * Get appropriate tabindex for accessibility\n */\n getIconTabIndex(): string {\n if (!this.clickable) return '-1';\n return this.disabled ? '-1' : '0';\n }\n\n /**\n * Get appropriate aria-disabled attribute\n */\n getAriaDisabled(): string | undefined {\n return this.clickable && this.disabled ? 'true' : undefined;\n }\n }\n\n return ClickableMixinClass as Constructor<ClickableCapable> & T;\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/icon/mixins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC"}
|
package/mixins/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/icon/mixins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,sBAAsB,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2023 Nuraly, Laabidi Aymen\n * SPDX-License-Identifier: MIT\n */\n\nexport * from './clickable-mixin.js';\n"]}
|