@liwe3/webcomponents 1.0.14 → 1.1.10
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/dist/AIMarkdownEditor.d.ts +35 -0
- package/dist/AIMarkdownEditor.d.ts.map +1 -0
- package/dist/AIMarkdownEditor.js +412 -0
- package/dist/AIMarkdownEditor.js.map +1 -0
- package/dist/AITextEditor.d.ts +183 -0
- package/dist/AITextEditor.d.ts.map +1 -0
- package/dist/AITextEditor.js +63 -27
- package/dist/AITextEditor.js.map +1 -1
- package/dist/ButtonToolbar.d.ts +35 -0
- package/dist/ButtonToolbar.d.ts.map +1 -0
- package/dist/ButtonToolbar.js +220 -0
- package/dist/ButtonToolbar.js.map +1 -0
- package/dist/CheckList.d.ts +31 -0
- package/dist/CheckList.d.ts.map +1 -0
- package/dist/CheckList.js +336 -0
- package/dist/CheckList.js.map +1 -0
- package/dist/ChunkUploader.d.ts +125 -0
- package/dist/ChunkUploader.d.ts.map +1 -0
- package/dist/ChunkUploader.js +756 -0
- package/dist/ChunkUploader.js.map +1 -0
- package/dist/ComicBalloon.d.ts +82 -0
- package/dist/ComicBalloon.d.ts.map +1 -0
- package/dist/ComicBalloon.js +346 -0
- package/dist/ComicBalloon.js.map +1 -0
- package/dist/ContainerBox.d.ts +112 -0
- package/dist/ContainerBox.d.ts.map +1 -0
- package/dist/ContainerBox.js +359 -0
- package/dist/ContainerBox.js.map +1 -0
- package/dist/DateSelector.d.ts +103 -0
- package/dist/DateSelector.d.ts.map +1 -0
- package/dist/Dialog.d.ts +102 -0
- package/dist/Dialog.d.ts.map +1 -0
- package/dist/Dialog.js +299 -0
- package/dist/Dialog.js.map +1 -0
- package/dist/Drawer.d.ts +63 -0
- package/dist/Drawer.d.ts.map +1 -0
- package/dist/Drawer.js +340 -0
- package/dist/Drawer.js.map +1 -0
- package/dist/ImageView.d.ts +42 -0
- package/dist/ImageView.d.ts.map +1 -0
- package/dist/ImageView.js +209 -0
- package/dist/ImageView.js.map +1 -0
- package/dist/MarkdownPreview.d.ts +25 -0
- package/dist/MarkdownPreview.d.ts.map +1 -0
- package/dist/MarkdownPreview.js +147 -0
- package/dist/MarkdownPreview.js.map +1 -0
- package/dist/PopoverMenu.d.ts +103 -0
- package/dist/PopoverMenu.d.ts.map +1 -0
- package/dist/ResizableCropper.d.ts +158 -0
- package/dist/ResizableCropper.d.ts.map +1 -0
- package/dist/ResizableCropper.js +562 -0
- package/dist/ResizableCropper.js.map +1 -0
- package/dist/SmartSelect.d.ts +100 -0
- package/dist/SmartSelect.d.ts.map +1 -0
- package/dist/SmartSelect.js +45 -2
- package/dist/SmartSelect.js.map +1 -1
- package/dist/Toast.d.ts +127 -0
- package/dist/Toast.d.ts.map +1 -0
- package/dist/Toast.js +79 -49
- package/dist/Toast.js.map +1 -1
- package/dist/TreeView.d.ts +84 -0
- package/dist/TreeView.d.ts.map +1 -0
- package/dist/TreeView.js +478 -0
- package/dist/TreeView.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +51 -14
- package/dist/index.js.map +1 -1
- package/package.json +60 -5
- package/src/AIMarkdownEditor.ts +568 -0
- package/src/AITextEditor.ts +97 -2
- package/src/ButtonToolbar.ts +302 -0
- package/src/CheckList.ts +438 -0
- package/src/ChunkUploader.ts +1135 -0
- package/src/ComicBalloon.ts +709 -0
- package/src/ContainerBox.ts +570 -0
- package/src/Dialog.ts +510 -0
- package/src/Drawer.ts +435 -0
- package/src/ImageView.ts +265 -0
- package/src/MarkdownPreview.ts +213 -0
- package/src/ResizableCropper.ts +1099 -0
- package/src/SmartSelect.ts +48 -2
- package/src/Toast.ts +96 -32
- package/src/TreeView.ts +673 -0
- package/src/index.ts +129 -27
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
class l extends HTMLElement {
|
|
2
|
+
constructor() {
|
|
3
|
+
super(), this._groups = [], this.attachShadow({ mode: "open" });
|
|
4
|
+
}
|
|
5
|
+
static get observedAttributes() {
|
|
6
|
+
return ["orientation", "groups"];
|
|
7
|
+
}
|
|
8
|
+
attributeChangedCallback(o, i, n) {
|
|
9
|
+
i !== n && this.render();
|
|
10
|
+
}
|
|
11
|
+
get orientation() {
|
|
12
|
+
return this.getAttribute("orientation") || "horizontal";
|
|
13
|
+
}
|
|
14
|
+
set orientation(o) {
|
|
15
|
+
this.setAttribute("orientation", o);
|
|
16
|
+
}
|
|
17
|
+
get groups() {
|
|
18
|
+
const o = this.getAttribute("groups");
|
|
19
|
+
if (o)
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(o);
|
|
22
|
+
} catch (i) {
|
|
23
|
+
return console.error("Invalid groups format:", i), [];
|
|
24
|
+
}
|
|
25
|
+
return this._groups;
|
|
26
|
+
}
|
|
27
|
+
set groups(o) {
|
|
28
|
+
this._groups = o, this.setAttribute("groups", JSON.stringify(o));
|
|
29
|
+
}
|
|
30
|
+
connectedCallback() {
|
|
31
|
+
this.render();
|
|
32
|
+
}
|
|
33
|
+
handleButtonClick(o, i) {
|
|
34
|
+
o.disabled || this.dispatchEvent(new CustomEvent("button-click", {
|
|
35
|
+
detail: {
|
|
36
|
+
id: o.id,
|
|
37
|
+
action: o.action || o.id,
|
|
38
|
+
originalEvent: i,
|
|
39
|
+
item: o
|
|
40
|
+
},
|
|
41
|
+
bubbles: !0,
|
|
42
|
+
composed: !0
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
render() {
|
|
46
|
+
if (!this.shadowRoot) return;
|
|
47
|
+
const o = `
|
|
48
|
+
:host {
|
|
49
|
+
display: block;
|
|
50
|
+
font-family: var(--liwe3-font-family, system-ui, -apple-system, sans-serif);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.toolbar {
|
|
54
|
+
display: flex;
|
|
55
|
+
gap: var(--liwe3-toolbar-gap, 0.5rem);
|
|
56
|
+
width: 100%;
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.toolbar.horizontal {
|
|
61
|
+
flex-direction: row;
|
|
62
|
+
align-items: center;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.toolbar.vertical {
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
align-items: stretch;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.group {
|
|
71
|
+
display: flex;
|
|
72
|
+
gap: 1px; /* Gap between buttons in a group */
|
|
73
|
+
background-color: var(--liwe3-toolbar-group-bg, transparent);
|
|
74
|
+
border-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.toolbar.horizontal .group {
|
|
79
|
+
flex-direction: row;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.toolbar.vertical .group {
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.button {
|
|
87
|
+
display: inline-flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
gap: 0.5rem;
|
|
91
|
+
padding: var(--liwe3-button-padding, 0.5rem 1rem);
|
|
92
|
+
border: none;
|
|
93
|
+
cursor: pointer;
|
|
94
|
+
font-size: var(--liwe3-button-font-size, 0.875rem);
|
|
95
|
+
line-height: 1.25;
|
|
96
|
+
transition: all 0.2s;
|
|
97
|
+
background-color: var(--liwe3-button-bg, #f3f4f6);
|
|
98
|
+
color: var(--liwe3-button-color, #1f2937);
|
|
99
|
+
min-height: var(--liwe3-button-height, 2.5rem);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.button:hover:not(:disabled) {
|
|
103
|
+
filter: brightness(0.95);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.button:active:not(:disabled) {
|
|
107
|
+
filter: brightness(0.9);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.button:disabled {
|
|
111
|
+
opacity: 0.5;
|
|
112
|
+
cursor: not-allowed;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Button Types */
|
|
116
|
+
.button.default {
|
|
117
|
+
background-color: var(--liwe3-button-default-bg, #f3f4f6);
|
|
118
|
+
color: var(--liwe3-button-default-color, #1f2937);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.button.info {
|
|
122
|
+
background-color: var(--liwe3-button-info-bg, #3b82f6);
|
|
123
|
+
color: var(--liwe3-button-info-color, #ffffff);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.button.error {
|
|
127
|
+
background-color: var(--liwe3-button-error-bg, #ef4444);
|
|
128
|
+
color: var(--liwe3-button-error-color, #ffffff);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.button.warn {
|
|
132
|
+
background-color: var(--liwe3-button-warn-bg, #f59e0b);
|
|
133
|
+
color: var(--liwe3-button-warn-color, #ffffff);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.button.success {
|
|
137
|
+
background-color: var(--liwe3-button-success-bg, #10b981);
|
|
138
|
+
color: var(--liwe3-button-success-color, #ffffff);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Content styling */
|
|
142
|
+
.icon {
|
|
143
|
+
width: 1.25em;
|
|
144
|
+
height: 1.25em;
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: center;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.icon svg {
|
|
151
|
+
width: 100%;
|
|
152
|
+
height: 100%;
|
|
153
|
+
fill: currentColor;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.image {
|
|
157
|
+
width: 1.5em;
|
|
158
|
+
height: 1.5em;
|
|
159
|
+
object-fit: cover;
|
|
160
|
+
border-radius: 50%;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Group styling - rounded corners logic */
|
|
164
|
+
.toolbar.horizontal .group .button:first-child {
|
|
165
|
+
border-top-left-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
166
|
+
border-bottom-left-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.toolbar.horizontal .group .button:last-child {
|
|
170
|
+
border-top-right-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
171
|
+
border-bottom-right-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.toolbar.vertical .group .button:first-child {
|
|
175
|
+
border-top-left-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
176
|
+
border-top-right-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.toolbar.vertical .group .button:last-child {
|
|
180
|
+
border-bottom-left-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
181
|
+
border-bottom-right-radius: var(--liwe3-toolbar-radius, 0.375rem);
|
|
182
|
+
}
|
|
183
|
+
`, i = (t) => {
|
|
184
|
+
const e = document.createElement("button");
|
|
185
|
+
if (e.className = `button ${t.type || "default"}`, t.disabled && (e.disabled = !0), t.tooltip && (e.title = t.tooltip), e.onclick = (r) => this.handleButtonClick(t, r), t.icon) {
|
|
186
|
+
const r = document.createElement("span");
|
|
187
|
+
if (r.className = "icon", t.icon.trim().startsWith("<"))
|
|
188
|
+
r.innerHTML = t.icon;
|
|
189
|
+
else {
|
|
190
|
+
const a = document.createElement("i");
|
|
191
|
+
a.className = t.icon, r.appendChild(a);
|
|
192
|
+
}
|
|
193
|
+
e.appendChild(r);
|
|
194
|
+
}
|
|
195
|
+
if (t.image) {
|
|
196
|
+
const r = document.createElement("img");
|
|
197
|
+
r.src = t.image, r.className = "image", r.alt = t.label || "", e.appendChild(r);
|
|
198
|
+
}
|
|
199
|
+
if (t.label) {
|
|
200
|
+
const r = document.createElement("span");
|
|
201
|
+
r.textContent = t.label, e.appendChild(r);
|
|
202
|
+
}
|
|
203
|
+
return e;
|
|
204
|
+
}, n = document.createElement("div");
|
|
205
|
+
n.className = `toolbar ${this.orientation}`, this._groups.forEach((t) => {
|
|
206
|
+
const e = document.createElement("div");
|
|
207
|
+
e.className = `group ${t.class || ""}`, t.items.forEach((r) => {
|
|
208
|
+
e.appendChild(i(r));
|
|
209
|
+
}), n.appendChild(e);
|
|
210
|
+
}), this.shadowRoot.innerHTML = `<style>${o}</style>`, this.shadowRoot.appendChild(n);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const u = () => {
|
|
214
|
+
typeof window < "u" && !customElements.get("liwe3-button-toolbar") && customElements.define("liwe3-button-toolbar", l);
|
|
215
|
+
};
|
|
216
|
+
export {
|
|
217
|
+
l as ButtonToolbarElement,
|
|
218
|
+
u as defineButtonToolbar
|
|
219
|
+
};
|
|
220
|
+
//# sourceMappingURL=ButtonToolbar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ButtonToolbar.js","sources":["../src/ButtonToolbar.ts"],"sourcesContent":["/**\n * ButtonToolbar Web Component\n * A customizable toolbar with groups of buttons, supporting horizontal/vertical orientation\n */\n\nexport type ButtonToolbarItem = {\n id: string;\n label?: string;\n icon?: string; // SVG content or icon class\n image?: string; // Image URL\n type?: 'default' | 'info' | 'error' | 'warn' | 'success';\n disabled?: boolean;\n tooltip?: string;\n action?: string; // Optional action name to dispatch\n};\n\nexport type ButtonToolbarGroup = {\n id?: string;\n items: ButtonToolbarItem[];\n class?: string; // Optional CSS class for the group\n};\n\nexport class ButtonToolbarElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private _groups: ButtonToolbarGroup[] = [];\n\n constructor() {\n super();\n this.attachShadow({ mode: 'open' });\n }\n\n static get observedAttributes(): string[] {\n return ['orientation', 'groups'];\n }\n\n attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue !== newValue) {\n this.render();\n }\n }\n\n get orientation(): 'horizontal' | 'vertical' {\n return (this.getAttribute('orientation') as 'horizontal' | 'vertical') || 'horizontal';\n }\n\n set orientation(value: 'horizontal' | 'vertical') {\n this.setAttribute('orientation', value);\n }\n\n get groups(): ButtonToolbarGroup[] {\n const groupsAttr = this.getAttribute('groups');\n if (groupsAttr) {\n try {\n return JSON.parse(groupsAttr);\n } catch (e) {\n console.error('Invalid groups format:', e);\n return [];\n }\n }\n return this._groups;\n }\n\n set groups(value: ButtonToolbarGroup[]) {\n this._groups = value;\n // Also update attribute for consistency, but be careful with large data\n // For now, let's just render. If we want to sync property to attribute:\n // this.setAttribute('groups', JSON.stringify(value));\n // But usually for complex data, property is preferred source of truth if set directly.\n \n // SmartSelect implementation:\n // set options ( opts: SelectOption[] ) {\n // this.setAttribute( 'options', JSON.stringify( opts ) );\n // }\n \n // I'll follow SmartSelect pattern for consistency\n this.setAttribute('groups', JSON.stringify(value));\n }\n\n connectedCallback(): void {\n this.render();\n }\n\n private handleButtonClick(item: ButtonToolbarItem, event: Event): void {\n if (item.disabled) return;\n \n this.dispatchEvent(new CustomEvent('button-click', {\n detail: {\n id: item.id,\n action: item.action || item.id,\n originalEvent: event,\n item\n },\n bubbles: true,\n composed: true\n }));\n }\n\n private render(): void {\n if (!this.shadowRoot) return;\n\n const style = `\n :host {\n display: block;\n font-family: var(--liwe3-font-family, system-ui, -apple-system, sans-serif);\n }\n\n .toolbar {\n display: flex;\n gap: var(--liwe3-toolbar-gap, 0.5rem);\n width: 100%;\n box-sizing: border-box;\n }\n\n .toolbar.horizontal {\n flex-direction: row;\n align-items: center;\n }\n\n .toolbar.vertical {\n flex-direction: column;\n align-items: stretch;\n }\n\n .group {\n display: flex;\n gap: 1px; /* Gap between buttons in a group */\n background-color: var(--liwe3-toolbar-group-bg, transparent);\n border-radius: var(--liwe3-toolbar-radius, 0.375rem);\n overflow: hidden;\n }\n\n .toolbar.horizontal .group {\n flex-direction: row;\n }\n\n .toolbar.vertical .group {\n flex-direction: column;\n }\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n padding: var(--liwe3-button-padding, 0.5rem 1rem);\n border: none;\n cursor: pointer;\n font-size: var(--liwe3-button-font-size, 0.875rem);\n line-height: 1.25;\n transition: all 0.2s;\n background-color: var(--liwe3-button-bg, #f3f4f6);\n color: var(--liwe3-button-color, #1f2937);\n min-height: var(--liwe3-button-height, 2.5rem);\n }\n\n .button:hover:not(:disabled) {\n filter: brightness(0.95);\n }\n\n .button:active:not(:disabled) {\n filter: brightness(0.9);\n }\n\n .button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n /* Button Types */\n .button.default {\n background-color: var(--liwe3-button-default-bg, #f3f4f6);\n color: var(--liwe3-button-default-color, #1f2937);\n }\n\n .button.info {\n background-color: var(--liwe3-button-info-bg, #3b82f6);\n color: var(--liwe3-button-info-color, #ffffff);\n }\n\n .button.error {\n background-color: var(--liwe3-button-error-bg, #ef4444);\n color: var(--liwe3-button-error-color, #ffffff);\n }\n\n .button.warn {\n background-color: var(--liwe3-button-warn-bg, #f59e0b);\n color: var(--liwe3-button-warn-color, #ffffff);\n }\n \n .button.success {\n background-color: var(--liwe3-button-success-bg, #10b981);\n color: var(--liwe3-button-success-color, #ffffff);\n }\n\n /* Content styling */\n .icon {\n width: 1.25em;\n height: 1.25em;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n .icon svg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n }\n\n .image {\n width: 1.5em;\n height: 1.5em;\n object-fit: cover;\n border-radius: 50%;\n }\n \n /* Group styling - rounded corners logic */\n .toolbar.horizontal .group .button:first-child {\n border-top-left-radius: var(--liwe3-toolbar-radius, 0.375rem);\n border-bottom-left-radius: var(--liwe3-toolbar-radius, 0.375rem);\n }\n \n .toolbar.horizontal .group .button:last-child {\n border-top-right-radius: var(--liwe3-toolbar-radius, 0.375rem);\n border-bottom-right-radius: var(--liwe3-toolbar-radius, 0.375rem);\n }\n \n .toolbar.vertical .group .button:first-child {\n border-top-left-radius: var(--liwe3-toolbar-radius, 0.375rem);\n border-top-right-radius: var(--liwe3-toolbar-radius, 0.375rem);\n }\n \n .toolbar.vertical .group .button:last-child {\n border-bottom-left-radius: var(--liwe3-toolbar-radius, 0.375rem);\n border-bottom-right-radius: var(--liwe3-toolbar-radius, 0.375rem);\n }\n `;\n\n const renderButton = (item: ButtonToolbarItem) => {\n const btn = document.createElement('button');\n btn.className = `button ${item.type || 'default'}`;\n if (item.disabled) btn.disabled = true;\n if (item.tooltip) btn.title = item.tooltip;\n \n btn.onclick = (e) => this.handleButtonClick(item, e);\n\n if (item.icon) {\n const iconSpan = document.createElement('span');\n iconSpan.className = 'icon';\n // Check if it's an SVG string or just a class name (simple heuristic)\n if (item.icon.trim().startsWith('<')) {\n iconSpan.innerHTML = item.icon;\n } else {\n // Assuming it might be a class name if not SVG\n const i = document.createElement('i');\n i.className = item.icon;\n iconSpan.appendChild(i);\n }\n btn.appendChild(iconSpan);\n }\n\n if (item.image) {\n const img = document.createElement('img');\n img.src = item.image;\n img.className = 'image';\n img.alt = item.label || '';\n btn.appendChild(img);\n }\n\n if (item.label) {\n const span = document.createElement('span');\n span.textContent = item.label;\n btn.appendChild(span);\n }\n\n return btn;\n };\n\n const container = document.createElement('div');\n container.className = `toolbar ${this.orientation}`;\n\n this._groups.forEach(group => {\n const groupDiv = document.createElement('div');\n groupDiv.className = `group ${group.class || ''}`;\n \n group.items.forEach(item => {\n groupDiv.appendChild(renderButton(item));\n });\n \n container.appendChild(groupDiv);\n });\n\n this.shadowRoot.innerHTML = `<style>${style}</style>`;\n this.shadowRoot.appendChild(container);\n }\n}\n\nexport const defineButtonToolbar = (): void => {\n if (typeof window !== 'undefined' && !customElements.get('liwe3-button-toolbar')) {\n customElements.define('liwe3-button-toolbar', ButtonToolbarElement);\n }\n};\n"],"names":["ButtonToolbarElement","_name","oldValue","newValue","value","groupsAttr","e","item","event","style","renderButton","btn","iconSpan","i","img","span","container","group","groupDiv","defineButtonToolbar"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CheckList Web Component
|
|
3
|
+
* A customizable checklist with progress bar and JSON support
|
|
4
|
+
*/
|
|
5
|
+
export type CheckListItem = {
|
|
6
|
+
label: string;
|
|
7
|
+
checked: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare class CheckListElement extends HTMLElement {
|
|
10
|
+
shadowRoot: ShadowRoot;
|
|
11
|
+
private _items;
|
|
12
|
+
private _title;
|
|
13
|
+
constructor();
|
|
14
|
+
static get observedAttributes(): string[];
|
|
15
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
16
|
+
get title(): string;
|
|
17
|
+
set title(value: string);
|
|
18
|
+
get items(): CheckListItem[];
|
|
19
|
+
set items(value: CheckListItem[]);
|
|
20
|
+
get percentage(): number;
|
|
21
|
+
loadJSON(json: string): void;
|
|
22
|
+
toJSON(): string;
|
|
23
|
+
private addItem;
|
|
24
|
+
private removeItem;
|
|
25
|
+
private toggleItem;
|
|
26
|
+
private updateItemLabel;
|
|
27
|
+
private render;
|
|
28
|
+
private bindEvents;
|
|
29
|
+
}
|
|
30
|
+
export declare const defineCheckList: (tagName?: string) => void;
|
|
31
|
+
//# sourceMappingURL=CheckList.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckList.d.ts","sourceRoot":"","sources":["../src/CheckList.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,qBAAa,gBAAiB,SAAQ,WAAW;IACvC,UAAU,EAAE,UAAU,CAAC;IAC/B,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,MAAM,CAAuB;;IAQrC,MAAM,KAAK,kBAAkB,IAAK,MAAM,EAAE,CAEzC;IAED,wBAAwB,CAAG,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAI,IAAI;IAejG,IAAI,KAAK,IAAK,MAAM,CAEnB;IAED,IAAI,KAAK,CAAG,KAAK,EAAE,MAAM,EAIxB;IAED,IAAI,KAAK,IAAK,aAAa,EAAE,CAE5B;IAED,IAAI,KAAK,CAAG,KAAK,EAAE,aAAa,EAAE,EAIjC;IAED,IAAI,UAAU,IAAK,MAAM,CAIxB;IAED,QAAQ,CAAG,IAAI,EAAE,MAAM,GAAI,IAAI;IAY/B,MAAM,IAAK,MAAM;IAOjB,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,MAAM;IA0Pd,OAAO,CAAC,UAAU;CA+DnB;AAED,eAAO,MAAM,eAAe,GAAK,UAAS,MAA0B,KAAI,IAIvE,CAAC"}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
class c extends HTMLElement {
|
|
2
|
+
constructor() {
|
|
3
|
+
super(), this._items = [], this._title = "Checklist", this.attachShadow({ mode: "open" }), this.render();
|
|
4
|
+
}
|
|
5
|
+
static get observedAttributes() {
|
|
6
|
+
return ["title", "items"];
|
|
7
|
+
}
|
|
8
|
+
attributeChangedCallback(t, e, i) {
|
|
9
|
+
if (e !== i) {
|
|
10
|
+
if (t === "title")
|
|
11
|
+
this._title = i || "Checklist";
|
|
12
|
+
else if (t === "items" && i)
|
|
13
|
+
try {
|
|
14
|
+
this._items = JSON.parse(i);
|
|
15
|
+
} catch (r) {
|
|
16
|
+
console.error("Invalid items JSON:", r);
|
|
17
|
+
}
|
|
18
|
+
this.render();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
get title() {
|
|
22
|
+
return this._title;
|
|
23
|
+
}
|
|
24
|
+
set title(t) {
|
|
25
|
+
this._title = t, this.setAttribute("title", t), this.render();
|
|
26
|
+
}
|
|
27
|
+
get items() {
|
|
28
|
+
return [...this._items];
|
|
29
|
+
}
|
|
30
|
+
set items(t) {
|
|
31
|
+
this._items = [...t], this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { items: this._items } }));
|
|
32
|
+
}
|
|
33
|
+
get percentage() {
|
|
34
|
+
if (this._items.length === 0) return 0;
|
|
35
|
+
const t = this._items.filter((e) => e.checked).length;
|
|
36
|
+
return Math.round(t / this._items.length * 100);
|
|
37
|
+
}
|
|
38
|
+
loadJSON(t) {
|
|
39
|
+
try {
|
|
40
|
+
const e = JSON.parse(t);
|
|
41
|
+
e.title && (this.title = e.title), e.items && Array.isArray(e.items) && (this.items = e.items);
|
|
42
|
+
} catch (e) {
|
|
43
|
+
console.error("Error loading JSON:", e);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
toJSON() {
|
|
47
|
+
return JSON.stringify({
|
|
48
|
+
title: this.title,
|
|
49
|
+
items: this.items
|
|
50
|
+
}, null, 2);
|
|
51
|
+
}
|
|
52
|
+
addItem(t) {
|
|
53
|
+
t.trim() && (this._items.push({ label: t, checked: !1 }), this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { items: this._items } })), requestAnimationFrame(() => {
|
|
54
|
+
const e = this.shadowRoot.querySelector(".add-item-input");
|
|
55
|
+
e && e.focus();
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
removeItem(t) {
|
|
59
|
+
this._items.splice(t, 1), this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { items: this._items } }));
|
|
60
|
+
}
|
|
61
|
+
toggleItem(t) {
|
|
62
|
+
this._items[t].checked = !this._items[t].checked, this.render(), this.dispatchEvent(new CustomEvent("change", { detail: { items: this._items } }));
|
|
63
|
+
}
|
|
64
|
+
updateItemLabel(t, e) {
|
|
65
|
+
this._items[t].label = e, this.dispatchEvent(new CustomEvent("change", { detail: { items: this._items } }));
|
|
66
|
+
}
|
|
67
|
+
render() {
|
|
68
|
+
const t = this.percentage, e = this._items.filter((n) => n.checked).length, i = this._items.length;
|
|
69
|
+
this.shadowRoot.querySelector(".list") || (this.shadowRoot.innerHTML = `
|
|
70
|
+
<style>
|
|
71
|
+
:host {
|
|
72
|
+
display: block;
|
|
73
|
+
font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);
|
|
74
|
+
background: var(--background, #fff);
|
|
75
|
+
border-radius: var(--border-radius, 8px);
|
|
76
|
+
padding: var(--padding, 16px);
|
|
77
|
+
box-shadow: var(--box-shadow, 0 2px 4px rgba(0,0,0,0.1));
|
|
78
|
+
max-width: var(--max-width, 100%);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.header {
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
justify-content: space-between;
|
|
85
|
+
margin-bottom: 16px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.title {
|
|
89
|
+
font-size: 1.1rem;
|
|
90
|
+
font-weight: 600;
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
gap: 8px;
|
|
94
|
+
color: var(--text-color, #333);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.title-icon {
|
|
98
|
+
width: 20px;
|
|
99
|
+
height: 20px;
|
|
100
|
+
fill: currentColor;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.progress-container {
|
|
104
|
+
display: flex;
|
|
105
|
+
align-items: center;
|
|
106
|
+
gap: 12px;
|
|
107
|
+
margin-bottom: 20px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.progress-text {
|
|
111
|
+
font-size: 0.9rem;
|
|
112
|
+
font-weight: 600;
|
|
113
|
+
color: var(--text-color, #333);
|
|
114
|
+
min-width: 40px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.progress-bar-bg {
|
|
118
|
+
flex: 1;
|
|
119
|
+
height: 6px;
|
|
120
|
+
background: #e0e0e0;
|
|
121
|
+
border-radius: 3px;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.progress-bar-fill {
|
|
126
|
+
height: 100%;
|
|
127
|
+
background: var(--primary-color, #1976d2);
|
|
128
|
+
width: 0%;
|
|
129
|
+
transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.list {
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
gap: 8px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.list-item {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
gap: 12px;
|
|
142
|
+
padding: 4px 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.checkbox {
|
|
146
|
+
width: 20px;
|
|
147
|
+
height: 20px;
|
|
148
|
+
border: 2px solid #757575;
|
|
149
|
+
border-radius: 4px;
|
|
150
|
+
cursor: pointer;
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
transition: all 0.2s;
|
|
155
|
+
flex-shrink: 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.checkbox.checked {
|
|
159
|
+
background: var(--primary-color, #1976d2);
|
|
160
|
+
border-color: var(--primary-color, #1976d2);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.checkbox svg {
|
|
164
|
+
width: 14px;
|
|
165
|
+
height: 14px;
|
|
166
|
+
fill: white;
|
|
167
|
+
display: none;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.checkbox.checked svg {
|
|
171
|
+
display: block;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.item-input {
|
|
175
|
+
flex: 1;
|
|
176
|
+
padding: 8px 12px;
|
|
177
|
+
border: 1px solid #e0e0e0;
|
|
178
|
+
border-radius: 4px;
|
|
179
|
+
font-size: 0.95rem;
|
|
180
|
+
outline: none;
|
|
181
|
+
transition: border-color 0.2s;
|
|
182
|
+
color: var(--text-color, #333);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.item-input:focus {
|
|
186
|
+
border-color: var(--primary-color, #1976d2);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.item-input.add-item-input {
|
|
190
|
+
color: #666;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.item-input.add-item-input::placeholder {
|
|
194
|
+
color: #999;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.delete-btn {
|
|
198
|
+
background: none;
|
|
199
|
+
border: none;
|
|
200
|
+
cursor: pointer;
|
|
201
|
+
padding: 4px;
|
|
202
|
+
color: #9e9e9e;
|
|
203
|
+
transition: color 0.2s;
|
|
204
|
+
display: flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
justify-content: center;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.delete-btn:hover {
|
|
210
|
+
color: #f44336;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.delete-btn svg {
|
|
214
|
+
width: 18px;
|
|
215
|
+
height: 18px;
|
|
216
|
+
fill: currentColor;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.add-btn {
|
|
220
|
+
background: #f5f5f5;
|
|
221
|
+
border: none;
|
|
222
|
+
border-radius: 50%;
|
|
223
|
+
width: 32px;
|
|
224
|
+
height: 32px;
|
|
225
|
+
display: flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
cursor: pointer;
|
|
229
|
+
color: #757575;
|
|
230
|
+
transition: background 0.2s;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.add-btn:hover {
|
|
234
|
+
background: #e0e0e0;
|
|
235
|
+
}
|
|
236
|
+
</style>
|
|
237
|
+
|
|
238
|
+
<div class="header">
|
|
239
|
+
<div class="title">
|
|
240
|
+
<svg class="title-icon" viewBox="0 0 24 24">
|
|
241
|
+
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>
|
|
242
|
+
</svg>
|
|
243
|
+
<span class="title-text">${this._title}</span>
|
|
244
|
+
</div>
|
|
245
|
+
<slot name="menu"></slot>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
<div class="progress-container">
|
|
249
|
+
<div class="progress-text"></div>
|
|
250
|
+
<div class="progress-bar-bg">
|
|
251
|
+
<div class="progress-bar-fill"></div>
|
|
252
|
+
</div>
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<div class="list"></div>
|
|
256
|
+
`);
|
|
257
|
+
const r = this.shadowRoot.querySelector(".title-text");
|
|
258
|
+
r && (r.textContent = this._title);
|
|
259
|
+
const s = this.shadowRoot.querySelector(".progress-text");
|
|
260
|
+
s && (s.textContent = `${e} / ${i}`);
|
|
261
|
+
const o = this.shadowRoot.querySelector(".progress-bar-fill");
|
|
262
|
+
o && (o.style.width = `${t}%`);
|
|
263
|
+
const l = this.shadowRoot.querySelector(".list");
|
|
264
|
+
l && (l.innerHTML = `
|
|
265
|
+
${this._items.map((n, a) => `
|
|
266
|
+
<div class="list-item">
|
|
267
|
+
<div class="checkbox ${n.checked ? "checked" : ""}" data-index="${a}">
|
|
268
|
+
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
|
|
269
|
+
</div>
|
|
270
|
+
<input
|
|
271
|
+
type="text"
|
|
272
|
+
class="item-input"
|
|
273
|
+
value="${n.label}"
|
|
274
|
+
data-index="${a}"
|
|
275
|
+
>
|
|
276
|
+
<button class="delete-btn" data-index="${a}" title="Delete item">
|
|
277
|
+
<svg viewBox="0 0 24 24">
|
|
278
|
+
<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
|
|
279
|
+
</svg>
|
|
280
|
+
</button>
|
|
281
|
+
</div>
|
|
282
|
+
`).join("")}
|
|
283
|
+
|
|
284
|
+
<div class="list-item">
|
|
285
|
+
<div class="checkbox" style="border-color: transparent; cursor: default;"></div>
|
|
286
|
+
<input
|
|
287
|
+
type="text"
|
|
288
|
+
class="item-input add-item-input"
|
|
289
|
+
placeholder="Add an item"
|
|
290
|
+
>
|
|
291
|
+
<div class="add-btn" title="Add item">
|
|
292
|
+
<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
|
|
293
|
+
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
|
294
|
+
</svg>
|
|
295
|
+
</div>
|
|
296
|
+
</div>
|
|
297
|
+
`), this.bindEvents();
|
|
298
|
+
}
|
|
299
|
+
bindEvents() {
|
|
300
|
+
this.shadowRoot.querySelectorAll(".checkbox").forEach((i) => {
|
|
301
|
+
i.addEventListener("click", (r) => {
|
|
302
|
+
const s = r.currentTarget.dataset.index;
|
|
303
|
+
s !== void 0 && this.toggleItem(parseInt(s));
|
|
304
|
+
});
|
|
305
|
+
}), this.shadowRoot.querySelectorAll(".delete-btn").forEach((i) => {
|
|
306
|
+
i.addEventListener("click", (r) => {
|
|
307
|
+
const s = r.currentTarget.dataset.index;
|
|
308
|
+
s !== void 0 && this.removeItem(parseInt(s));
|
|
309
|
+
});
|
|
310
|
+
}), this.shadowRoot.querySelectorAll(".item-input:not(.add-item-input)").forEach((i) => {
|
|
311
|
+
i.addEventListener("input", (r) => {
|
|
312
|
+
const s = r.target, o = s.dataset.index;
|
|
313
|
+
o !== void 0 && this.updateItemLabel(parseInt(o), s.value);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
const t = this.shadowRoot.querySelector(".add-item-input");
|
|
317
|
+
t && (t.addEventListener("keydown", (i) => {
|
|
318
|
+
i.key === "Enter" && (this.addItem(t.value), t.value = "");
|
|
319
|
+
}), t.addEventListener("blur", () => {
|
|
320
|
+
t.value.trim() && (this.addItem(t.value), t.value = "");
|
|
321
|
+
}));
|
|
322
|
+
const e = this.shadowRoot.querySelector(".add-btn");
|
|
323
|
+
e && t && e.addEventListener("click", () => {
|
|
324
|
+
t.value.trim() ? (this.addItem(t.value), t.value = "") : t.focus();
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const h = (d = "liwe3-checklist") => {
|
|
329
|
+
typeof window < "u" && !window.customElements.get(d) && customElements.define(d, c);
|
|
330
|
+
};
|
|
331
|
+
h();
|
|
332
|
+
export {
|
|
333
|
+
c as CheckListElement,
|
|
334
|
+
h as defineCheckList
|
|
335
|
+
};
|
|
336
|
+
//# sourceMappingURL=CheckList.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckList.js","sources":["../src/CheckList.ts"],"sourcesContent":["/**\n * CheckList Web Component\n * A customizable checklist with progress bar and JSON support\n */\n\nexport type CheckListItem = {\n label: string;\n checked: boolean;\n};\n\nexport class CheckListElement extends HTMLElement {\n declare shadowRoot: ShadowRoot;\n private _items: CheckListItem[] = [];\n private _title: string = 'Checklist';\n\n constructor () {\n super();\n this.attachShadow( { mode: 'open' } );\n this.render();\n }\n\n static get observedAttributes (): string[] {\n return [ 'title', 'items' ];\n }\n\n attributeChangedCallback ( name: string, oldValue: string | null, newValue: string | null ): void {\n if ( oldValue !== newValue ) {\n if ( name === 'title' ) {\n this._title = newValue || 'Checklist';\n } else if ( name === 'items' && newValue ) {\n try {\n this._items = JSON.parse( newValue );\n } catch ( e ) {\n console.error( 'Invalid items JSON:', e );\n }\n }\n this.render();\n }\n }\n\n get title (): string {\n return this._title;\n }\n\n set title ( value: string ) {\n this._title = value;\n this.setAttribute( 'title', value );\n this.render();\n }\n\n get items (): CheckListItem[] {\n return [ ...this._items ];\n }\n\n set items ( value: CheckListItem[] ) {\n this._items = [ ...value ];\n this.render();\n this.dispatchEvent( new CustomEvent( 'change', { detail: { items: this._items } } ) );\n }\n\n get percentage (): number {\n if ( this._items.length === 0 ) return 0;\n const completed = this._items.filter( item => item.checked ).length;\n return Math.round( ( completed / this._items.length ) * 100 );\n }\n\n loadJSON ( json: string ): void {\n try {\n const data = JSON.parse( json );\n if ( data.title ) this.title = data.title;\n if ( data.items && Array.isArray( data.items ) ) {\n this.items = data.items;\n }\n } catch ( e ) {\n console.error( 'Error loading JSON:', e );\n }\n }\n\n toJSON (): string {\n return JSON.stringify( {\n title: this.title,\n items: this.items\n }, null, 2 );\n }\n\n private addItem ( label: string ): void {\n if ( !label.trim() ) return;\n this._items.push( { label, checked: false } );\n this.render();\n this.dispatchEvent( new CustomEvent( 'change', { detail: { items: this._items } } ) );\n \n // Focus the new add item input after rendering\n requestAnimationFrame( () => {\n const addInput = this.shadowRoot.querySelector( '.add-item-input' ) as HTMLInputElement;\n if ( addInput ) addInput.focus();\n } );\n }\n\n private removeItem ( index: number ): void {\n this._items.splice( index, 1 );\n this.render();\n this.dispatchEvent( new CustomEvent( 'change', { detail: { items: this._items } } ) );\n }\n\n private toggleItem ( index: number ): void {\n this._items[ index ].checked = !this._items[ index ].checked;\n this.render();\n this.dispatchEvent( new CustomEvent( 'change', { detail: { items: this._items } } ) );\n }\n\n private updateItemLabel ( index: number, label: string ): void {\n this._items[ index ].label = label;\n // We don't re-render here to avoid losing focus, just update the model\n this.dispatchEvent( new CustomEvent( 'change', { detail: { items: this._items } } ) );\n }\n\n private render (): void {\n const percentage = this.percentage;\n const completedCount = this._items.filter( i => i.checked ).length;\n const totalCount = this._items.length;\n\n // Initial render of structure if needed\n if ( !this.shadowRoot.querySelector( '.list' ) ) {\n this.shadowRoot.innerHTML = `\n <style>\n :host {\n display: block;\n font-family: var(--font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n background: var(--background, #fff);\n border-radius: var(--border-radius, 8px);\n padding: var(--padding, 16px);\n box-shadow: var(--box-shadow, 0 2px 4px rgba(0,0,0,0.1));\n max-width: var(--max-width, 100%);\n }\n \n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n }\n \n .title {\n font-size: 1.1rem;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--text-color, #333);\n }\n \n .title-icon {\n width: 20px;\n height: 20px;\n fill: currentColor;\n }\n \n .progress-container {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n }\n \n .progress-text {\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--text-color, #333);\n min-width: 40px;\n }\n \n .progress-bar-bg {\n flex: 1;\n height: 6px;\n background: #e0e0e0;\n border-radius: 3px;\n overflow: hidden;\n }\n \n .progress-bar-fill {\n height: 100%;\n background: var(--primary-color, #1976d2);\n width: 0%;\n transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n \n .list-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 4px 0;\n }\n \n .checkbox {\n width: 20px;\n height: 20px;\n border: 2px solid #757575;\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n flex-shrink: 0;\n }\n \n .checkbox.checked {\n background: var(--primary-color, #1976d2);\n border-color: var(--primary-color, #1976d2);\n }\n \n .checkbox svg {\n width: 14px;\n height: 14px;\n fill: white;\n display: none;\n }\n \n .checkbox.checked svg {\n display: block;\n }\n \n .item-input {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid #e0e0e0;\n border-radius: 4px;\n font-size: 0.95rem;\n outline: none;\n transition: border-color 0.2s;\n color: var(--text-color, #333);\n }\n \n .item-input:focus {\n border-color: var(--primary-color, #1976d2);\n }\n \n .item-input.add-item-input {\n color: #666;\n }\n \n .item-input.add-item-input::placeholder {\n color: #999;\n }\n \n .delete-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 4px;\n color: #9e9e9e;\n transition: color 0.2s;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n .delete-btn:hover {\n color: #f44336;\n }\n \n .delete-btn svg {\n width: 18px;\n height: 18px;\n fill: currentColor;\n }\n \n .add-btn {\n background: #f5f5f5;\n border: none;\n border-radius: 50%;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n color: #757575;\n transition: background 0.2s;\n }\n \n .add-btn:hover {\n background: #e0e0e0;\n }\n </style>\n \n <div class=\"header\">\n <div class=\"title\">\n <svg class=\"title-icon\" viewBox=\"0 0 24 24\">\n <path d=\"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z\"/>\n </svg>\n <span class=\"title-text\">${ this._title }</span>\n </div>\n <slot name=\"menu\"></slot>\n </div>\n \n <div class=\"progress-container\">\n <div class=\"progress-text\"></div>\n <div class=\"progress-bar-bg\">\n <div class=\"progress-bar-fill\"></div>\n </div>\n </div>\n \n <div class=\"list\"></div>\n `;\n }\n\n // Update Title\n const titleText = this.shadowRoot.querySelector( '.title-text' );\n if ( titleText ) titleText.textContent = this._title;\n\n // Update Progress\n const progressText = this.shadowRoot.querySelector( '.progress-text' );\n if ( progressText ) progressText.textContent = `${ completedCount } / ${ totalCount }`;\n\n const progressBar = this.shadowRoot.querySelector( '.progress-bar-fill' ) as HTMLElement;\n if ( progressBar ) progressBar.style.width = `${ percentage }%`;\n\n // Update List\n const list = this.shadowRoot.querySelector( '.list' );\n if ( list ) {\n list.innerHTML = `\n ${ this._items.map( ( item, index ) => `\n <div class=\"list-item\">\n <div class=\"checkbox ${ item.checked ? 'checked' : '' }\" data-index=\"${ index }\">\n <svg viewBox=\"0 0 24 24\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg>\n </div>\n <input \n type=\"text\" \n class=\"item-input\" \n value=\"${ item.label }\" \n data-index=\"${ index }\"\n >\n <button class=\"delete-btn\" data-index=\"${ index }\" title=\"Delete item\">\n <svg viewBox=\"0 0 24 24\">\n <path d=\"M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z\"/>\n </svg>\n </button>\n </div>\n `).join( '' ) }\n\n <div class=\"list-item\">\n <div class=\"checkbox\" style=\"border-color: transparent; cursor: default;\"></div>\n <input \n type=\"text\" \n class=\"item-input add-item-input\" \n placeholder=\"Add an item\"\n >\n <div class=\"add-btn\" title=\"Add item\">\n <svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\">\n <path d=\"M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\"/>\n </svg>\n </div>\n </div>\n `;\n }\n\n this.bindEvents();\n }\n\n private bindEvents (): void {\n // Checkbox toggle\n this.shadowRoot.querySelectorAll( '.checkbox' ).forEach( checkbox => {\n checkbox.addEventListener( 'click', ( e ) => {\n const index = ( e.currentTarget as HTMLElement ).dataset.index;\n if ( index !== undefined ) {\n this.toggleItem( parseInt( index ) );\n }\n } );\n } );\n\n // Delete button\n this.shadowRoot.querySelectorAll( '.delete-btn' ).forEach( btn => {\n btn.addEventListener( 'click', ( e ) => {\n const index = ( e.currentTarget as HTMLElement ).dataset.index;\n if ( index !== undefined ) {\n this.removeItem( parseInt( index ) );\n }\n } );\n } );\n\n // Item input update\n this.shadowRoot.querySelectorAll( '.item-input:not(.add-item-input)' ).forEach( input => {\n input.addEventListener( 'input', ( e ) => {\n const target = e.target as HTMLInputElement;\n const index = target.dataset.index;\n if ( index !== undefined ) {\n this.updateItemLabel( parseInt( index ), target.value );\n }\n } );\n } );\n\n // Add item input\n const addInput = this.shadowRoot.querySelector( '.add-item-input' ) as HTMLInputElement;\n if ( addInput ) {\n addInput.addEventListener( 'keydown', ( e ) => {\n if ( e.key === 'Enter' ) {\n this.addItem( addInput.value );\n addInput.value = '';\n }\n } );\n \n addInput.addEventListener( 'blur', () => {\n if ( addInput.value.trim() ) {\n this.addItem( addInput.value );\n addInput.value = '';\n }\n } );\n }\n \n // Add button click\n const addBtn = this.shadowRoot.querySelector( '.add-btn' );\n if ( addBtn && addInput ) {\n addBtn.addEventListener( 'click', () => {\n if ( addInput.value.trim() ) {\n this.addItem( addInput.value );\n addInput.value = '';\n } else {\n addInput.focus();\n }\n } );\n }\n }\n}\n\nexport const defineCheckList = ( tagName: string = 'liwe3-checklist' ): void => {\n if ( typeof window !== 'undefined' && !window.customElements.get( tagName ) ) {\n customElements.define( tagName, CheckListElement );\n }\n};\n\ndefineCheckList();\n"],"names":["CheckListElement","name","oldValue","newValue","e","value","completed","item","json","data","label","addInput","index","percentage","completedCount","i","totalCount","titleText","progressText","progressBar","list","checkbox","btn","input","target","addBtn","defineCheckList","tagName"],"mappings":"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"}
|