@wsxjs/wsx-base-components 0.0.8 → 0.0.9

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.
@@ -0,0 +1,146 @@
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
+ }
@@ -0,0 +1,256 @@
1
+ /** @jsxImportSource @wsxjs/wsx-core */
2
+ /**
3
+ * UserProfileLight Component - LightComponent with @state object support
4
+ *
5
+ * Demonstrates:
6
+ * - Using @state decorator with objects in LightComponent
7
+ * - Object property updates trigger automatic rerender
8
+ * - Object replacement (entire object replacement)
9
+ * - Nested object updates
10
+ * - Light DOM (no Shadow DOM) - styles can be inherited from parent
11
+ */
12
+
13
+ import { LightComponent, state, autoRegister, createLogger } from "@wsxjs/wsx-core";
14
+ import "./UserProfileLight.css";
15
+
16
+ const logger = createLogger("UserProfileLight");
17
+
18
+ interface UserPreferences {
19
+ theme: "light" | "dark";
20
+ language: string;
21
+ notifications: boolean;
22
+ }
23
+
24
+ interface UserProfile {
25
+ name: string;
26
+ email: string;
27
+ age: number;
28
+ preferences: UserPreferences;
29
+ lastLogin: number;
30
+ }
31
+
32
+ @autoRegister({ tagName: "user-profile-light" })
33
+ export default class UserProfileLight extends LightComponent {
34
+ // @state decorator with object - automatically reactive
35
+ @state private profile: UserProfile = {
36
+ name: "John Doe",
37
+ email: "john@example.com",
38
+ age: 30,
39
+ preferences: {
40
+ theme: "light",
41
+ language: "en",
42
+ notifications: true,
43
+ },
44
+ lastLogin: Date.now(),
45
+ };
46
+
47
+ constructor() {
48
+ super();
49
+ logger.info("UserProfileLight initialized");
50
+ }
51
+
52
+ render() {
53
+ return (
54
+ <div class="user-profile">
55
+ <div class="profile-header">
56
+ <h2>👤 User Profile (LightComponent)</h2>
57
+ <p class="subtitle">Demonstrates @state decorator with objects</p>
58
+ </div>
59
+
60
+ <div class="profile-content">
61
+ <div class="profile-section">
62
+ <h3>Basic Information</h3>
63
+ <div class="form-group">
64
+ <label>Name:</label>
65
+ <input
66
+ type="text"
67
+ value={this.profile.name}
68
+ onInput={this.handleNameChange}
69
+ onBlur={this.handleNameBlur}
70
+ class="input-field"
71
+ />
72
+ </div>
73
+ <div class="form-group">
74
+ <label>Email:</label>
75
+ <input
76
+ type="email"
77
+ value={this.profile.email}
78
+ onInput={this.handleEmailChange}
79
+ onBlur={this.handleEmailBlur}
80
+ class="input-field"
81
+ />
82
+ </div>
83
+ <div class="form-group">
84
+ <label>Age:</label>
85
+ <input
86
+ type="number"
87
+ value={this.profile.age.toString()}
88
+ onInput={this.handleAgeChange}
89
+ onBlur={this.handleAgeBlur}
90
+ class="input-field"
91
+ />
92
+ </div>
93
+ </div>
94
+
95
+ <div class="profile-section">
96
+ <h3>Preferences</h3>
97
+ <div class="form-group">
98
+ <label>Theme:</label>
99
+ <select
100
+ value={this.profile.preferences.theme}
101
+ onChange={this.handleThemeChange}
102
+ class="input-field"
103
+ >
104
+ <option value="light">Light</option>
105
+ <option value="dark">Dark</option>
106
+ </select>
107
+ </div>
108
+ <div class="form-group">
109
+ <label>Language:</label>
110
+ <select
111
+ value={this.profile.preferences.language}
112
+ onChange={this.handleLanguageChange}
113
+ class="input-field"
114
+ >
115
+ <option value="en">English</option>
116
+ <option value="zh">中文</option>
117
+ <option value="es">Español</option>
118
+ <option value="fr">Français</option>
119
+ </select>
120
+ </div>
121
+ <div class="form-group">
122
+ <label>
123
+ <input
124
+ type="checkbox"
125
+ checked={this.profile.preferences.notifications}
126
+ onChange={this.handleNotificationsChange}
127
+ />
128
+ Enable Notifications
129
+ </label>
130
+ </div>
131
+ </div>
132
+
133
+ <div class="profile-actions">
134
+ <button class="btn btn-primary" onClick={this.resetProfile}>
135
+ Reset to Default
136
+ </button>
137
+ <button class="btn btn-secondary" onClick={this.updateLastLogin}>
138
+ Update Last Login
139
+ </button>
140
+ <button class="btn btn-warning" onClick={this.replaceEntireProfile}>
141
+ Replace Entire Profile
142
+ </button>
143
+ </div>
144
+
145
+ <div class="profile-display">
146
+ <h3>Current Profile Data</h3>
147
+ <pre class="json-display">{JSON.stringify(this.profile, null, 2)}</pre>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ );
152
+ }
153
+
154
+ private handleNameChange = (event: Event) => {
155
+ const input = event.target as HTMLInputElement;
156
+ // Update non-reactive property - no rerender
157
+ this.profile.name = input.value;
158
+ };
159
+
160
+ private handleNameBlur = () => {
161
+ // Update reactive profile when input loses focus
162
+ this.profile = { ...this.profile, name: this.profile.name };
163
+ logger.debug("Name updated", { name: this.profile.name });
164
+ };
165
+
166
+ private handleEmailChange = (event: Event) => {
167
+ const input = event.target as HTMLInputElement;
168
+ // Update non-reactive property - no rerender
169
+ this.profile.email = input.value;
170
+ };
171
+
172
+ private handleEmailBlur = () => {
173
+ // Update reactive profile when input loses focus
174
+ this.profile = { ...this.profile, email: this.profile.email };
175
+ logger.debug("Email updated", { email: this.profile.email });
176
+ };
177
+
178
+ private handleAgeChange = (event: Event) => {
179
+ const input = event.target as HTMLInputElement;
180
+ // Update non-reactive property - no rerender
181
+ this.profile.age = parseInt(input.value, 10) || 0;
182
+ };
183
+
184
+ private handleAgeBlur = () => {
185
+ // Update reactive profile when input loses focus
186
+ this.profile = { ...this.profile, age: this.profile.age };
187
+ logger.debug("Age updated", { age: this.profile.age });
188
+ };
189
+
190
+ private handleThemeChange = (event: Event) => {
191
+ const select = event.target as HTMLSelectElement;
192
+ // Direct nested property update - automatically reactive
193
+ this.profile.preferences.theme = select.value as "light" | "dark";
194
+ logger.debug("Theme updated", { theme: select.value });
195
+ };
196
+
197
+ private handleLanguageChange = (event: Event) => {
198
+ const select = event.target as HTMLSelectElement;
199
+ // Direct nested property update - automatically reactive
200
+ this.profile.preferences.language = select.value;
201
+ logger.debug("Language updated", { language: select.value });
202
+ };
203
+
204
+ private handleNotificationsChange = (event: Event) => {
205
+ const checkbox = event.target as HTMLInputElement;
206
+ // Direct nested property update - automatically reactive
207
+ this.profile.preferences.notifications = checkbox.checked;
208
+ logger.debug("Notifications updated", { notifications: checkbox.checked });
209
+ };
210
+
211
+ private resetProfile = () => {
212
+ // Replace entire object - automatically wrapped in reactive
213
+ this.profile = {
214
+ name: "John Doe",
215
+ email: "john@example.com",
216
+ age: 30,
217
+ preferences: {
218
+ theme: "light",
219
+ language: "en",
220
+ notifications: true,
221
+ },
222
+ lastLogin: Date.now(),
223
+ };
224
+ // Sync non-reactive input values
225
+ this._name = "John Doe";
226
+ this._email = "john@example.com";
227
+ this._age = 30;
228
+ logger.debug("Profile reset to default");
229
+ };
230
+
231
+ private updateLastLogin = () => {
232
+ // Update object property - automatically reactive
233
+ this.profile = { ...this.profile, lastLogin: Date.now() };
234
+ logger.debug("Last login updated", { lastLogin: this.profile.lastLogin });
235
+ };
236
+
237
+ private replaceEntireProfile = () => {
238
+ // Replace entire object - automatically wrapped in reactive
239
+ this.profile = {
240
+ name: "Jane Smith",
241
+ email: "jane@example.com",
242
+ age: 25,
243
+ preferences: {
244
+ theme: "dark",
245
+ language: "zh",
246
+ notifications: false,
247
+ },
248
+ lastLogin: Date.now(),
249
+ };
250
+ // Sync non-reactive input values
251
+ this._name = "Jane Smith";
252
+ this._email = "jane@example.com";
253
+ this._age = 25;
254
+ logger.debug("Entire profile replaced");
255
+ };
256
+ }
package/src/index.ts CHANGED
@@ -9,6 +9,10 @@ export { default as ThemeSwitcher } from "./ThemeSwitcher.wsx";
9
9
  export { default as SvgIcon } from "./SvgIcon.wsx";
10
10
  export { default as SvgDemo } from "./SvgDemo.wsx";
11
11
  export { default as SimpleReactiveDemo } from "./SimpleReactiveDemo.wsx";
12
+ export { default as TodoList } from "./TodoList.wsx";
13
+ export { default as TodoListLight } from "./TodoListLight.wsx";
14
+ export { default as UserProfile } from "./UserProfile.wsx";
15
+ export { default as UserProfileLight } from "./UserProfileLight.wsx";
12
16
 
13
17
  // Export utilities
14
18
  export * from "./ColorPickerUtils";