@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.
@@ -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;AAG1C,qBACa,UAAW,SAAQ,UAAU;IACxC,gBAAyB,MAAM,0BAa7B;IACO,MAAM;CAchB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,UAAU,CAAC;KAC5B;CACF"}
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"}
@@ -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
- <h3>Default icon (solid)</h3>
13
- <hy-icon name="envelope"></hy-icon>
14
- <h3>Icon with overriden color</h3>
15
- <hy-icon id="first-icon" name="check"></hy-icon>
16
- <h3>Icon with overriden size</h3>
17
- <hy-icon id="second-icon" name="warning"></hy-icon>
18
- <h3>Icon with overriden size and color</h3>
19
- <hy-icon id="third-icon" name="bug"></hy-icon>
20
- <h3>Regular icon</h3>
21
- <hy-icon name="envelope" type="regular"></hy-icon>
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
- #first-icon {
27
- --hybrid-icon-color: red;
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
- #second-icon {
30
- --hybrid-icon-width: 20px;
31
- --hybrid-icon-height: 25px;
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
- #third-icon {
34
- --hybrid-icon-width: 30px;
35
- --hybrid-icon-height: 35px;
36
- --hybrid-icon-color: green;
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);
@@ -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;AAGhD,IAAa,UAAU,GAAvB,MAAa,UAAW,SAAQ,UAAU;IAe/B,MAAM;QACb,OAAO,IAAI,CAAA;;;;;;;;;;;KAWV,CAAC;IACJ,CAAC;CACF,CAAA;AA5B0B,iBAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;GAanC,CAAA;AAdS,UAAU;IADtB,aAAa,CAAC,cAAc,CAAC;GACjB,UAAU,CA6BtB;SA7BY,UAAU","sourcesContent":["import {LitElement, css, html} from 'lit';\nimport {customElement} from 'lit/decorators.js';\n\n@customElement('hy-icon-demo')\nexport class HyIconDemo extends LitElement {\n static override readonly styles = css`\n #first-icon {\n --hybrid-icon-color: red;\n }\n #second-icon {\n --hybrid-icon-width: 20px;\n --hybrid-icon-height: 25px;\n }\n #third-icon {\n --hybrid-icon-width: 30px;\n --hybrid-icon-height: 35px;\n --hybrid-icon-color: green;\n }\n `;\n override render() {\n return html`\n <h3>Default icon (solid)</h3>\n <hy-icon name=\"envelope\"></hy-icon>\n <h3>Icon with overriden color</h3>\n <hy-icon id=\"first-icon\" name=\"check\"></hy-icon>\n <h3>Icon with overriden size</h3>\n <hy-icon id=\"second-icon\" name=\"warning\"></hy-icon>\n <h3>Icon with overriden size and color</h3>\n <hy-icon id=\"third-icon\" name=\"bug\"></hy-icon>\n <h3>Regular icon</h3>\n <hy-icon name=\"envelope\" type=\"regular\"></hy-icon>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hy-icon-demo': HyIconDemo;\n }\n}\n"]}
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"]}
@@ -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
- export declare class HyIconElement extends LitElement {
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
- static readonly styles: import("lit").CSSResult[];
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(): any;
15
- }
16
- declare global {
17
- interface HTMLElementTagNameMap {
18
- 'hy-icon': HyIconElement;
19
- }
20
- namespace JSX {
21
- interface IntrinsicElements {
22
- 'hy-icon': React.DetailedHTMLProps<React.HTMLAttributes<HyIconElement>, HyIconElement> | Partial<HyIconElement>;
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
@@ -1 +1 @@
1
- {"version":3,"file":"icon.component.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.component.ts"],"names":[],"mappings":"AACA;;;;GAIG;;AAEH,OAAO,EAAC,UAAU,EAAO,MAAM,KAAK,CAAC;AASrC,OAAO,EAAC,SAAS,EAAiC,MAAM,iBAAiB,CAAC;AAE1E,qBACa,aAAc,SAAQ,UAAU;IAE3C,IAAI,EAAG,MAAM,CAAC;IAEd,IAAI,YAAmB;IAEvB,gBAAyB,MAAM,4BAAU;IAChC,MAAM;IAOf,WAAW;CAKZ;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,SAAS,EAAE,aAAa,CAAC;KAC1B;IAED,UAAU,GAAG,CAAC;QACZ,UAAU,iBAAiB;YACzB,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,cAAc,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;SACjH;KACF;CACF"}
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
- let HyIconElement = class HyIconElement extends LitElement {
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 class="svg-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 550 550">
30
- <path d="${this.getIconPath()}" />
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
- const iconDefinition = library.definitions[iconPack][this.name];
37
- return iconDefinition ? iconDefinition[4] : '';
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);
@@ -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,EAAC,UAAU,EAAE,IAAI,EAAC,MAAM,KAAK,CAAC;AACrC,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAC,OAAO,EAAE,GAAG,EAAC,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAC,GAAG,EAAC,MAAM,qCAAqC,CAAC;AACxD,OAAO,EAAC,GAAG,EAAC,MAAM,mCAAmC,CAAC;AACtD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACtB,GAAG,CAAC,KAAK,EAAE,CAAC;AAEZ,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAY,eAAe,EAAE,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAG1E,IAAa,aAAa,GAA1B,MAAa,aAAc,SAAQ,UAAU;IAA7C;;QAIE,SAAI,iCAAmB;IAezB,CAAC;IAZU,MAAM;QACb,OAAO,IAAI,CAAA;;mBAEI,IAAI,CAAC,WAAW,EAAE;;KAEhC,CAAC;IACJ,CAAC;IACD,WAAW;QACT,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,iCAAmB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAC;QAChF,MAAM,cAAc,GAAI,OAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzE,OAAO,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjD,CAAC;CACF,CAAA;AAb0B,oBAAM,GAAG,MAAO,CAAA;AAJzC;IADC,QAAQ,CAAC,EAAC,IAAI,EAAE,MAAM,EAAC,CAAC;2CACX;AAEd;IADC,QAAQ,EAAE;2CACY;AAJZ,aAAa;IADzB,aAAa,CAAC,SAAS,CAAC;GACZ,aAAa,CAmBzB;SAnBY,aAAa","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';\n\n@customElement('hy-icon')\nexport class HyIconElement extends LitElement {\n @property({type: String})\n name!: string;\n @property()\n type = IconTypes.Solid;\n\n static override readonly styles = styles;\n override render() {\n return html`\n <svg class=\"svg-icon\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 550 550\">\n <path d=\"${this.getIconPath()}\" />\n </svg>\n `;\n }\n getIconPath() {\n const iconPack = this.type == IconTypes.Solid ? solidIconPack : regularIconPack;\n const iconDefinition = (library as any).definitions[iconPack][this.name];\n return iconDefinition ? iconDefinition[4] : '';\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hy-icon': HyIconElement;\n }\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n 'hy-icon': React.DetailedHTMLProps<React.HTMLAttributes<HyIconElement>, HyIconElement> | Partial<HyIconElement>;\n }\n }\n}\n"]}
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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"icon.style.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.style.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,MAAM,2BAA+B,CAAC"}
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
- fill: var(--hybrid-icon-color, #000000);
6
- width: var(--hybrid-icon-width);
7
- height: var(--hybrid-icon-height);
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;;;;;;CAMrB,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\nconst iconStyles = css`\n .svg-icon {\n fill: var(--hybrid-icon-color, #000000);\n width: var(--hybrid-icon-width);\n height: var(--hybrid-icon-height);\n }\n`;\nexport const styles = [iconStyles, styleVariables];\n"]}
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"]}
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"icon.variables.d.ts","sourceRoot":"","sources":["../../../src/components/icon/icon.variables.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,yBAW1B,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
- /* --hybrid-icon-color: #000000; */
5
- --hybrid-icon-width: 18px;
6
- --hybrid-icon-height: 18px;
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
- @media (prefers-color-scheme: dark) {
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-color: #ffffff;
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
  `;
@@ -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;;;;;;;;;;;CAWhC,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styleVariables = css`\n :host {\n /* --hybrid-icon-color: #000000; */\n --hybrid-icon-width: 18px;\n --hybrid-icon-height: 18px;\n }\n @media (prefers-color-scheme: dark) {\n :host {\n --hybrid-icon-color: #ffffff;\n }\n }\n`;\n"]}
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,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Nuraly, Laabidi Aymen
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export * from './clickable-mixin.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2023 Nuraly, Laabidi Aymen
4
+ * SPDX-License-Identifier: MIT
5
+ */
6
+ export * from './clickable-mixin.js';
7
+ //# sourceMappingURL=index.js.map
@@ -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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuralyui/icon",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "type": "module",