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