@wsxjs/wsx-base-components 0.0.16 → 0.0.18

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.
Files changed (42) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +28 -28
  3. package/dist/index.cjs +14 -2
  4. package/dist/index.js +4971 -2032
  5. package/dist/style.css +1 -1
  6. package/package.json +16 -7
  7. package/src/{XyButton.css → Button.css} +1 -1
  8. package/src/{XyButton.wsx → Button.wsx} +18 -9
  9. package/src/ButtonGroup.css +30 -0
  10. package/src/{XyButtonGroup.wsx → ButtonGroup.wsx} +26 -14
  11. package/src/CodeBlock.css +275 -0
  12. package/src/CodeBlock.types.ts +25 -0
  13. package/src/CodeBlock.wsx +296 -0
  14. package/src/ColorPicker.wsx +6 -5
  15. package/src/Combobox.css +254 -0
  16. package/src/Combobox.types.ts +32 -0
  17. package/src/Combobox.wsx +352 -0
  18. package/src/Dropdown.css +178 -0
  19. package/src/Dropdown.types.ts +28 -0
  20. package/src/Dropdown.wsx +221 -0
  21. package/src/LanguageSwitcher.css +148 -0
  22. package/src/LanguageSwitcher.wsx +190 -0
  23. package/src/OverflowDetector.ts +169 -0
  24. package/src/ResponsiveNav.css +555 -0
  25. package/src/ResponsiveNav.types.ts +30 -0
  26. package/src/ResponsiveNav.wsx +450 -0
  27. package/src/SvgIcon.wsx +2 -2
  28. package/src/index.ts +17 -9
  29. package/src/types/wsx.d.ts +4 -3
  30. package/src/ReactiveCounter.css +0 -304
  31. package/src/ReactiveCounter.wsx +0 -231
  32. package/src/SimpleReactiveDemo.wsx +0 -59
  33. package/src/SvgDemo.wsx +0 -241
  34. package/src/TodoList.css +0 -197
  35. package/src/TodoList.wsx +0 -264
  36. package/src/TodoListLight.css +0 -198
  37. package/src/TodoListLight.wsx +0 -263
  38. package/src/UserProfile.css +0 -146
  39. package/src/UserProfile.wsx +0 -247
  40. package/src/UserProfileLight.css +0 -146
  41. package/src/UserProfileLight.wsx +0 -256
  42. package/src/XyButtonGroup.css +0 -30
@@ -1,198 +0,0 @@
1
- .todo-list-light {
2
- padding: 1.5rem;
3
- max-width: 600px;
4
- margin: 0 auto;
5
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
6
- /* Light DOM - styles can be inherited from parent */
7
- }
8
-
9
- .todo-header {
10
- margin-bottom: 1.5rem;
11
- text-align: center;
12
- }
13
-
14
- .todo-header h2 {
15
- margin: 0 0 0.5rem 0;
16
- color: #2196f3;
17
- font-size: 1.75rem;
18
- }
19
-
20
- .subtitle {
21
- margin: 0;
22
- color: #666;
23
- font-size: 0.9rem;
24
- }
25
-
26
- .todo-input-section {
27
- display: flex;
28
- gap: 0.5rem;
29
- margin-bottom: 1rem;
30
- }
31
-
32
- .todo-input {
33
- flex: 1;
34
- padding: 0.75rem;
35
- border: 2px solid #ddd;
36
- border-radius: 4px;
37
- font-size: 1rem;
38
- transition: border-color 0.2s;
39
- }
40
-
41
- .todo-input:focus {
42
- outline: none;
43
- border-color: #2196f3;
44
- }
45
-
46
- .todo-filters {
47
- display: flex;
48
- gap: 0.5rem;
49
- margin-bottom: 1rem;
50
- justify-content: center;
51
- }
52
-
53
- .filter-btn {
54
- padding: 0.5rem 1rem;
55
- border: 2px solid #ddd;
56
- background: white;
57
- border-radius: 4px;
58
- cursor: pointer;
59
- transition: all 0.2s;
60
- font-size: 0.9rem;
61
- }
62
-
63
- .filter-btn:hover {
64
- background: #f5f5f5;
65
- }
66
-
67
- .filter-btn.active {
68
- background: #2196f3;
69
- color: white;
70
- border-color: #2196f3;
71
- }
72
-
73
- .todo-list-container {
74
- min-height: 200px;
75
- margin-bottom: 1rem;
76
- }
77
-
78
- .empty-state {
79
- text-align: center;
80
- padding: 3rem 1rem;
81
- color: #999;
82
- font-style: italic;
83
- }
84
-
85
- .todo-items {
86
- list-style: none;
87
- padding: 0;
88
- margin: 0;
89
- }
90
-
91
- .todo-item {
92
- display: flex;
93
- align-items: center;
94
- gap: 0.75rem;
95
- padding: 0.75rem;
96
- margin-bottom: 0.5rem;
97
- background: #f0f7ff;
98
- border-radius: 4px;
99
- transition: background 0.2s;
100
- }
101
-
102
- .todo-item:hover {
103
- background: #e3f2fd;
104
- }
105
-
106
- .todo-item.completed {
107
- opacity: 0.6;
108
- }
109
-
110
- .todo-checkbox {
111
- width: 1.25rem;
112
- height: 1.25rem;
113
- cursor: pointer;
114
- }
115
-
116
- .todo-text {
117
- flex: 1;
118
- font-size: 1rem;
119
- }
120
-
121
- .todo-item.completed .todo-text {
122
- text-decoration: line-through;
123
- color: #999;
124
- }
125
-
126
- .todo-actions {
127
- display: flex;
128
- gap: 0.5rem;
129
- justify-content: center;
130
- margin-top: 1rem;
131
- }
132
-
133
- .btn {
134
- padding: 0.5rem 1rem;
135
- border: none;
136
- border-radius: 4px;
137
- cursor: pointer;
138
- font-size: 0.9rem;
139
- transition: all 0.2s;
140
- }
141
-
142
- .btn:disabled {
143
- opacity: 0.5;
144
- cursor: not-allowed;
145
- }
146
-
147
- .btn-primary {
148
- background: #2196f3;
149
- color: white;
150
- }
151
-
152
- .btn-primary:hover:not(:disabled) {
153
- background: #1976d2;
154
- }
155
-
156
- .btn-warning {
157
- background: #ff9800;
158
- color: white;
159
- }
160
-
161
- .btn-warning:hover {
162
- background: #e68900;
163
- }
164
-
165
- .btn-danger {
166
- background: #f44336;
167
- color: white;
168
- }
169
-
170
- .btn-danger:hover {
171
- background: #da190b;
172
- }
173
-
174
- .btn-sm {
175
- padding: 0.25rem 0.5rem;
176
- font-size: 0.8rem;
177
- }
178
-
179
- .debug-info {
180
- margin-top: 2rem;
181
- padding-top: 1rem;
182
- border-top: 1px solid #ddd;
183
- }
184
-
185
- .debug-info summary {
186
- cursor: pointer;
187
- color: #666;
188
- font-size: 0.9rem;
189
- }
190
-
191
- .debug-info pre {
192
- background: #f5f5f5;
193
- padding: 1rem;
194
- border-radius: 4px;
195
- overflow-x: auto;
196
- font-size: 0.85rem;
197
- margin-top: 0.5rem;
198
- }
@@ -1,263 +0,0 @@
1
- /** @jsxImportSource @wsxjs/wsx-core */
2
- /**
3
- * TodoListLight Component - LightComponent with @state array support
4
- *
5
- * Demonstrates:
6
- * - Using @state decorator with arrays in LightComponent
7
- * - Array operations: add, remove, update, toggle
8
- * - Reactive array updates trigger automatic rerender
9
- * - Light DOM (no Shadow DOM) - styles can be inherited from parent
10
- */
11
-
12
- import { LightComponent, state, autoRegister, createLogger } from "@wsxjs/wsx-core";
13
- import "./TodoListLight.css";
14
-
15
- const logger = createLogger("TodoListLight");
16
-
17
- interface TodoItem {
18
- id: number;
19
- text: string;
20
- completed: boolean;
21
- createdAt: number;
22
- }
23
-
24
- @autoRegister({ tagName: "todo-list-light" })
25
- export default class TodoListLight extends LightComponent {
26
- // @state decorator with array - automatically reactive
27
- @state private todos: TodoItem[] = [];
28
-
29
- // Non-reactive input value - prevents rerender on every keystroke
30
- private _newTodoText = "";
31
-
32
- // @state decorator with filter state
33
- @state private filter: "all" | "active" | "completed" = "all";
34
-
35
- private nextId = 1;
36
-
37
- constructor() {
38
- super();
39
- logger.info("TodoListLight initialized");
40
- }
41
-
42
- render() {
43
- const filteredTodos = this.getFilteredTodos();
44
-
45
- return (
46
- <div class="todo-list-light">
47
- <div class="todo-header">
48
- <h2>📝 Todo List (LightComponent)</h2>
49
- <p class="subtitle">
50
- {this.todos.length} total, {this.getActiveCount()} active,{" "}
51
- {this.getCompletedCount()} completed
52
- </p>
53
- </div>
54
-
55
- <div class="todo-input-section">
56
- <input
57
- type="text"
58
- class="todo-input"
59
- placeholder="Add a new todo..."
60
- value={this._newTodoText}
61
- onInput={this.handleInputChange}
62
- onKeyDown={this.handleKeyDown}
63
- />
64
- <button
65
- class="btn btn-primary"
66
- onClick={this.addTodo}
67
- disabled={!this._newTodoText.trim()}
68
- >
69
- Add
70
- </button>
71
- </div>
72
-
73
- <div class="todo-filters">
74
- <button
75
- class={`filter-btn ${this.filter === "all" ? "active" : ""}`}
76
- onClick={() => (this.filter = "all")}
77
- >
78
- All ({this.todos.length})
79
- </button>
80
- <button
81
- class={`filter-btn ${this.filter === "active" ? "active" : ""}`}
82
- onClick={() => (this.filter = "active")}
83
- >
84
- Active ({this.getActiveCount()})
85
- </button>
86
- <button
87
- class={`filter-btn ${this.filter === "completed" ? "active" : ""}`}
88
- onClick={() => (this.filter = "completed")}
89
- >
90
- Completed ({this.getCompletedCount()})
91
- </button>
92
- </div>
93
-
94
- <div class="todo-list-container">
95
- {filteredTodos.length === 0 ? (
96
- <div class="empty-state">
97
- {this.filter === "all"
98
- ? "No todos yet. Add one above! 🎉"
99
- : `No ${this.filter} todos.`}
100
- </div>
101
- ) : (
102
- <ul class="todo-items">
103
- {filteredTodos.map((todo) => (
104
- <li
105
- key={todo.id}
106
- class={`todo-item ${todo.completed ? "completed" : ""}`}
107
- >
108
- <input
109
- type="checkbox"
110
- checked={todo.completed}
111
- onChange={() => this.toggleTodo(todo.id)}
112
- class="todo-checkbox"
113
- />
114
- <span class="todo-text">{todo.text}</span>
115
- <button
116
- class="btn btn-sm btn-danger"
117
- onClick={() => this.removeTodo(todo.id)}
118
- >
119
- Delete
120
- </button>
121
- </li>
122
- ))}
123
- </ul>
124
- )}
125
- </div>
126
-
127
- {this.todos.length > 0 && (
128
- <div class="todo-actions">
129
- <button class="btn btn-warning" onClick={this.clearCompleted}>
130
- Clear Completed
131
- </button>
132
- <button class="btn btn-danger" onClick={this.clearAll}>
133
- Clear All
134
- </button>
135
- </div>
136
- )}
137
-
138
- <div class="debug-info">
139
- <details>
140
- <summary>Debug Info</summary>
141
- <pre>
142
- {JSON.stringify(
143
- {
144
- todosCount: this.todos.length,
145
- filter: this.filter,
146
- newTodoText: this._newTodoText,
147
- todos: this.todos,
148
- },
149
- null,
150
- 2
151
- )}
152
- </pre>
153
- </details>
154
- </div>
155
- </div>
156
- );
157
- }
158
-
159
- private handleInputChange = (event: Event) => {
160
- const input = event.target as HTMLInputElement;
161
- // Update non-reactive state without triggering rerender
162
- this._newTodoText = input.value;
163
- // Update button disabled state directly without rerender
164
- const button = this.querySelector(".todo-input-section .btn-primary") as HTMLButtonElement;
165
- if (button) {
166
- button.disabled = !this._newTodoText.trim();
167
- }
168
- };
169
-
170
- private handleKeyDown = (event: KeyboardEvent) => {
171
- if (event.key === "Enter" && this._newTodoText.trim()) {
172
- this.addTodo();
173
- }
174
- };
175
-
176
- private addTodo = () => {
177
- // Get input value directly from DOM to avoid state sync issues
178
- const input = this.querySelector(".todo-input") as HTMLInputElement;
179
- const text = input?.value.trim() || this._newTodoText.trim();
180
-
181
- if (!text) {
182
- return;
183
- }
184
-
185
- // Array mutation - automatically reactive (triggers rerender)
186
- this.todos = [
187
- ...this.todos,
188
- {
189
- id: this.nextId++,
190
- text,
191
- completed: false,
192
- createdAt: Date.now(),
193
- },
194
- ];
195
-
196
- // Clear input - update both state and DOM
197
- this._newTodoText = "";
198
- if (input) {
199
- input.value = "";
200
- // Update button state
201
- const button = this.querySelector(
202
- ".todo-input-section .btn-primary"
203
- ) as HTMLButtonElement;
204
- if (button) {
205
- button.disabled = true;
206
- }
207
- }
208
- logger.debug("Todo added", { count: this.todos.length });
209
- };
210
-
211
- private removeTodo = (id: number) => {
212
- // Array filter - creates new array, automatically reactive
213
- this.todos = this.todos.filter((todo) => todo.id !== id);
214
- logger.debug("Todo removed", { id, remaining: this.todos.length });
215
- };
216
-
217
- private toggleTodo = (id: number) => {
218
- // Array map - creates new array with updated item, automatically reactive
219
- this.todos = this.todos.map((todo) =>
220
- todo.id === id ? { ...todo, completed: !todo.completed } : todo
221
- );
222
- logger.debug("Todo toggled", { id });
223
- };
224
-
225
- private clearCompleted = () => {
226
- // Array filter - removes all completed items
227
- this.todos = this.todos.filter((todo) => !todo.completed);
228
- logger.debug("Completed todos cleared");
229
- };
230
-
231
- private clearAll = () => {
232
- // Array assignment - clears all items
233
- this.todos = [];
234
- logger.debug("All todos cleared");
235
- };
236
-
237
- private getFilteredTodos(): TodoItem[] {
238
- switch (this.filter) {
239
- case "active":
240
- return this.todos.filter((todo) => !todo.completed);
241
- case "completed":
242
- return this.todos.filter((todo) => todo.completed);
243
- default:
244
- return this.todos;
245
- }
246
- }
247
-
248
- private getActiveCount(): number {
249
- return this.todos.filter((todo) => !todo.completed).length;
250
- }
251
-
252
- private getCompletedCount(): number {
253
- return this.todos.filter((todo) => todo.completed).length;
254
- }
255
-
256
- protected onConnected(): void {
257
- logger.info("TodoListLight connected to DOM");
258
- }
259
-
260
- protected onDisconnected(): void {
261
- logger.info("TodoListLight disconnected from DOM");
262
- }
263
- }
@@ -1,146 +0,0 @@
1
- .user-profile {
2
- padding: 1.5rem;
3
- max-width: 800px;
4
- margin: 0 auto;
5
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
6
- }
7
-
8
- .profile-header {
9
- margin-bottom: 2rem;
10
- text-align: center;
11
- }
12
-
13
- .profile-header h2 {
14
- margin: 0 0 0.5rem 0;
15
- color: #333;
16
- font-size: 1.75rem;
17
- }
18
-
19
- .profile-header .subtitle {
20
- color: #666;
21
- font-size: 0.9rem;
22
- margin: 0;
23
- }
24
-
25
- .profile-content {
26
- display: flex;
27
- flex-direction: column;
28
- gap: 2rem;
29
- }
30
-
31
- .profile-section {
32
- background: #f8f9fa;
33
- padding: 1.5rem;
34
- border-radius: 8px;
35
- border: 1px solid #e0e0e0;
36
- }
37
-
38
- .profile-section h3 {
39
- margin: 0 0 1rem 0;
40
- color: #333;
41
- font-size: 1.25rem;
42
- border-bottom: 2px solid #007bff;
43
- padding-bottom: 0.5rem;
44
- }
45
-
46
- .form-group {
47
- margin-bottom: 1rem;
48
- }
49
-
50
- .form-group label {
51
- display: block;
52
- margin-bottom: 0.5rem;
53
- color: #555;
54
- font-weight: 500;
55
- font-size: 0.9rem;
56
- }
57
-
58
- .form-group input[type="checkbox"] {
59
- margin-right: 0.5rem;
60
- }
61
-
62
- .input-field {
63
- width: 100%;
64
- padding: 0.75rem;
65
- border: 1px solid #ddd;
66
- border-radius: 4px;
67
- font-size: 1rem;
68
- transition: border-color 0.2s;
69
- box-sizing: border-box;
70
- }
71
-
72
- .input-field:focus {
73
- outline: none;
74
- border-color: #007bff;
75
- box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
76
- }
77
-
78
- .profile-actions {
79
- display: flex;
80
- gap: 1rem;
81
- flex-wrap: wrap;
82
- }
83
-
84
- .btn {
85
- padding: 0.75rem 1.5rem;
86
- border: none;
87
- border-radius: 4px;
88
- font-size: 1rem;
89
- cursor: pointer;
90
- transition: all 0.2s;
91
- font-weight: 500;
92
- }
93
-
94
- .btn-primary {
95
- background: #007bff;
96
- color: white;
97
- }
98
-
99
- .btn-primary:hover {
100
- background: #0056b3;
101
- }
102
-
103
- .btn-secondary {
104
- background: #6c757d;
105
- color: white;
106
- }
107
-
108
- .btn-secondary:hover {
109
- background: #545b62;
110
- }
111
-
112
- .btn-warning {
113
- background: #ffc107;
114
- color: #212529;
115
- }
116
-
117
- .btn-warning:hover {
118
- background: #e0a800;
119
- }
120
-
121
- .profile-display {
122
- background: #f8f9fa;
123
- padding: 1.5rem;
124
- border-radius: 8px;
125
- border: 1px solid #e0e0e0;
126
- }
127
-
128
- .profile-display h3 {
129
- margin: 0 0 1rem 0;
130
- color: #333;
131
- font-size: 1.25rem;
132
- }
133
-
134
- .json-display {
135
- background: #2d2d2d;
136
- color: #f8f8f2;
137
- padding: 1rem;
138
- border-radius: 4px;
139
- overflow-x: auto;
140
- font-family: "Courier New", monospace;
141
- font-size: 0.875rem;
142
- line-height: 1.5;
143
- margin: 0;
144
- white-space: pre-wrap;
145
- word-wrap: break-word;
146
- }