@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,304 +0,0 @@
1
- .reactive-counter {
2
- max-width: 500px;
3
- margin: 20px auto;
4
- padding: 24px;
5
- border-radius: 12px;
6
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
7
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
8
- transition: all 0.3s ease;
9
- }
10
-
11
- .theme-light {
12
- background: #ffffff;
13
- color: #333333;
14
- border: 1px solid #e1e5e9;
15
- }
16
-
17
- .theme-dark {
18
- background: #1a1a1a;
19
- color: #ffffff;
20
- border: 1px solid #333333;
21
- }
22
-
23
- .theme-blue {
24
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
25
- color: #ffffff;
26
- border: 1px solid #5a67d8;
27
- }
28
-
29
- .header {
30
- text-align: center;
31
- margin-bottom: 24px;
32
- }
33
-
34
- .header h3 {
35
- margin: 0 0 8px 0;
36
- font-size: 24px;
37
- font-weight: 600;
38
- }
39
-
40
- .subtitle {
41
- margin: 0;
42
- opacity: 0.8;
43
- font-size: 14px;
44
- }
45
-
46
- .counter-display {
47
- text-align: center;
48
- margin-bottom: 32px;
49
- }
50
-
51
- .count-value {
52
- font-size: 48px;
53
- font-weight: bold;
54
- line-height: 1;
55
- margin-bottom: 8px;
56
- font-variant-numeric: tabular-nums;
57
- }
58
-
59
- .step-info {
60
- font-size: 14px;
61
- opacity: 0.7;
62
- }
63
-
64
- .controls {
65
- display: flex;
66
- gap: 12px;
67
- justify-content: center;
68
- margin-bottom: 24px;
69
- flex-wrap: wrap;
70
- }
71
-
72
- .btn {
73
- padding: 10px 20px;
74
- border: none;
75
- border-radius: 8px;
76
- font-size: 16px;
77
- font-weight: 500;
78
- cursor: pointer;
79
- transition: all 0.2s ease;
80
- min-width: 60px;
81
- }
82
-
83
- .btn:disabled {
84
- opacity: 0.5;
85
- cursor: not-allowed;
86
- }
87
-
88
- .btn-primary {
89
- background: #4299e1;
90
- color: white;
91
- }
92
-
93
- .btn-primary:hover:not(:disabled) {
94
- background: #3182ce;
95
- transform: translateY(-1px);
96
- }
97
-
98
- .btn-secondary {
99
- background: #718096;
100
- color: white;
101
- }
102
-
103
- .btn-secondary:hover:not(:disabled) {
104
- background: #4a5568;
105
- transform: translateY(-1px);
106
- }
107
-
108
- .btn-warning {
109
- background: #ed8936;
110
- color: white;
111
- }
112
-
113
- .btn-warning:hover:not(:disabled) {
114
- background: #dd6b20;
115
- transform: translateY(-1px);
116
- }
117
-
118
- .btn-success {
119
- background: #48bb78;
120
- color: white;
121
- }
122
-
123
- .btn-success:hover:not(:disabled) {
124
- background: #38a169;
125
- transform: translateY(-1px);
126
- }
127
-
128
- .btn-danger {
129
- background: #f56565;
130
- color: white;
131
- }
132
-
133
- .btn-danger:hover:not(:disabled) {
134
- background: #e53e3e;
135
- transform: translateY(-1px);
136
- }
137
-
138
- .btn-sm {
139
- padding: 6px 12px;
140
- font-size: 14px;
141
- min-width: auto;
142
- }
143
-
144
- .step-controls,
145
- .auto-controls,
146
- .theme-controls,
147
- .message-controls {
148
- margin-bottom: 20px;
149
- text-align: center;
150
- }
151
-
152
- .step-controls label {
153
- display: flex;
154
- align-items: center;
155
- justify-content: center;
156
- gap: 12px;
157
- font-size: 14px;
158
- }
159
-
160
- .step-controls input[type="range"] {
161
- flex: 0 0 150px;
162
- }
163
-
164
- .step-controls span {
165
- font-weight: bold;
166
- min-width: 20px;
167
- }
168
-
169
- .theme-controls select,
170
- .message-controls input {
171
- padding: 8px 12px;
172
- border: 1px solid #cbd5e0;
173
- border-radius: 6px;
174
- font-size: 14px;
175
- margin-left: 8px;
176
- }
177
-
178
- .theme-dark .theme-controls select,
179
- .theme-dark .message-controls input {
180
- background: #2d3748;
181
- border-color: #4a5568;
182
- color: #ffffff;
183
- }
184
-
185
- .theme-blue .theme-controls select,
186
- .theme-blue .message-controls input {
187
- background: rgba(255, 255, 255, 0.1);
188
- border-color: rgba(255, 255, 255, 0.2);
189
- color: #ffffff;
190
- }
191
-
192
- .message-controls input {
193
- width: 250px;
194
- max-width: 100%;
195
- }
196
-
197
- .history {
198
- margin-top: 24px;
199
- padding: 16px;
200
- background: rgba(0, 0, 0, 0.05);
201
- border-radius: 8px;
202
- }
203
-
204
- .theme-dark .history {
205
- background: rgba(255, 255, 255, 0.05);
206
- }
207
-
208
- .theme-blue .history {
209
- background: rgba(255, 255, 255, 0.1);
210
- }
211
-
212
- .history h4 {
213
- margin: 0 0 12px 0;
214
- font-size: 16px;
215
- }
216
-
217
- .history-list {
218
- display: flex;
219
- flex-wrap: wrap;
220
- gap: 8px;
221
- margin-bottom: 12px;
222
- }
223
-
224
- .history-item {
225
- padding: 4px 8px;
226
- background: rgba(66, 153, 225, 0.1);
227
- border: 1px solid rgba(66, 153, 225, 0.2);
228
- border-radius: 4px;
229
- font-size: 12px;
230
- font-weight: 500;
231
- }
232
-
233
- .debug-info {
234
- margin-top: 24px;
235
- font-size: 12px;
236
- }
237
-
238
- .debug-info details {
239
- border: 1px solid #e2e8f0;
240
- border-radius: 6px;
241
- padding: 8px;
242
- }
243
-
244
- .theme-dark .debug-info details {
245
- border-color: #4a5568;
246
- }
247
-
248
- .theme-blue .debug-info details {
249
- border-color: rgba(255, 255, 255, 0.2);
250
- }
251
-
252
- .debug-info summary {
253
- cursor: pointer;
254
- font-weight: 500;
255
- margin-bottom: 8px;
256
- }
257
-
258
- .debug-info pre {
259
- margin: 0;
260
- padding: 8px;
261
- background: rgba(0, 0, 0, 0.05);
262
- border-radius: 4px;
263
- overflow-x: auto;
264
- font-size: 11px;
265
- line-height: 1.4;
266
- }
267
-
268
- .theme-dark .debug-info pre {
269
- background: rgba(255, 255, 255, 0.05);
270
- }
271
-
272
- .theme-blue .debug-info pre {
273
- background: rgba(255, 255, 255, 0.1);
274
- }
275
-
276
- /* 响应式设计 */
277
- @media (max-width: 600px) {
278
- .reactive-counter {
279
- margin: 10px;
280
- padding: 16px;
281
- }
282
-
283
- .count-value {
284
- font-size: 36px;
285
- }
286
-
287
- .controls {
288
- flex-direction: column;
289
- align-items: center;
290
- }
291
-
292
- .btn {
293
- width: 200px;
294
- }
295
-
296
- .step-controls label {
297
- flex-direction: column;
298
- gap: 8px;
299
- }
300
-
301
- .message-controls input {
302
- width: 100%;
303
- }
304
- }
@@ -1,231 +0,0 @@
1
- /** @jsxImportSource @wsxjs/wsx-core */
2
- /**
3
- * 响应式计数器组件 - 展示 WSX 响应式状态系统
4
- *
5
- * 这个组件演示了:
6
- * - 自动重渲染:状态变化时无需手动调用 rerender()
7
- * - 批量更新:多个状态变化会被合并为一次重渲染
8
- * - 原生性能:基于浏览器 Proxy API,零运行时开销
9
- * - 使用 @state 装饰器:自动初始化响应式状态
10
- */
11
-
12
- import { WebComponent, state, autoRegister, createLogger } from "@wsxjs/wsx-core";
13
-
14
- const logger = createLogger("ReactiveCounter");
15
-
16
- @autoRegister({ tagName: "reactive-counter" })
17
- export default class ReactiveCounter extends WebComponent {
18
- // 使用 @state 装饰器 - 自动初始化为响应式状态
19
- @state private state = {
20
- count: 0,
21
- step: 1,
22
- message: "Hello WSX Reactive!",
23
- isRunning: false,
24
- };
25
-
26
- // 使用 @state 装饰器 - 基本类型自动使用 useState
27
- @state private theme = "light";
28
- @state private history: number[] = [];
29
-
30
- constructor() {
31
- super();
32
-
33
- logger.info("ReactiveCounter initialized");
34
- }
35
-
36
- render() {
37
- return (
38
- <div class={`reactive-counter theme-${this.theme}`}>
39
- <div class="header">
40
- <h3>🔄 Reactive Counter</h3>
41
- <p class="subtitle">{this.state.message}</p>
42
- </div>
43
-
44
- <div class="counter-display">
45
- <div class="count-value">{this.state.count}</div>
46
- <div class="step-info">Step: {this.state.step}</div>
47
- </div>
48
-
49
- <div class="controls">
50
- <button
51
- class="btn btn-primary"
52
- onClick={this.increment}
53
- disabled={this.state.isRunning}
54
- >
55
- +{this.state.step}
56
- </button>
57
-
58
- <button
59
- class="btn btn-secondary"
60
- onClick={this.decrement}
61
- disabled={this.state.isRunning}
62
- >
63
- -{this.state.step}
64
- </button>
65
-
66
- <button
67
- class="btn btn-warning"
68
- onClick={this.reset}
69
- disabled={this.state.isRunning}
70
- >
71
- Reset
72
- </button>
73
- </div>
74
-
75
- <div class="step-controls">
76
- <label>
77
- Step Size:
78
- <input
79
- type="range"
80
- min="1"
81
- max="10"
82
- value={this.state.step}
83
- onInput={this.handleStepChange}
84
- />
85
- <span>{this.state.step}</span>
86
- </label>
87
- </div>
88
-
89
- <div class="auto-controls">
90
- <button
91
- class={`btn ${this.state.isRunning ? "btn-danger" : "btn-success"}`}
92
- onClick={this.toggleAutoIncrement}
93
- >
94
- {this.state.isRunning ? "Stop" : "Start"} Auto Increment
95
- </button>
96
- </div>
97
-
98
- <div class="theme-controls">
99
- <label>
100
- Theme:
101
- <select value={this.theme} onChange={this.handleThemeChange}>
102
- <option value="light">Light</option>
103
- <option value="dark">Dark</option>
104
- <option value="blue">Blue</option>
105
- </select>
106
- </label>
107
- </div>
108
-
109
- <div class="message-controls">
110
- <input
111
- type="text"
112
- value={this.state.message}
113
- onInput={this.handleMessageChange}
114
- placeholder="Enter a message..."
115
- />
116
- </div>
117
-
118
- {this.history.length > 0 && (
119
- <div class="history">
120
- <h4>History (last 10):</h4>
121
- <div class="history-list">
122
- {this.history.slice(-10).map((value, index) => (
123
- <span key={index} class="history-item">
124
- {value}
125
- </span>
126
- ))}
127
- </div>
128
- <button class="btn btn-sm" onClick={this.clearHistory}>
129
- Clear History
130
- </button>
131
- </div>
132
- )}
133
-
134
- <div class="debug-info">
135
- <details>
136
- <summary>Debug Info</summary>
137
- <pre>
138
- {JSON.stringify(
139
- {
140
- state: this.state,
141
- theme: this.theme,
142
- historyLength: this.history.length,
143
- },
144
- null,
145
- 2
146
- )}
147
- </pre>
148
- </details>
149
- </div>
150
- </div>
151
- );
152
- }
153
-
154
- // 事件处理方法 - 直接修改状态,自动触发重渲染
155
- private increment = () => {
156
- this.state.count += this.state.step;
157
- this.addToHistory(this.state.count);
158
- };
159
-
160
- private decrement = () => {
161
- this.state.count -= this.state.step;
162
- this.addToHistory(this.state.count);
163
- };
164
-
165
- private reset = () => {
166
- this.state.count = 0;
167
- this.addToHistory(0);
168
- };
169
-
170
- private handleStepChange = (event: Event) => {
171
- const input = event.target as HTMLInputElement;
172
- this.state.step = parseInt(input.value);
173
- };
174
-
175
- private handleThemeChange = (event: Event) => {
176
- const select = event.target as HTMLSelectElement;
177
- this.theme = select.value;
178
- };
179
-
180
- private handleMessageChange = (event: Event) => {
181
- const input = event.target as HTMLInputElement;
182
- this.state.message = input.value;
183
- };
184
-
185
- private toggleAutoIncrement = () => {
186
- this.state.isRunning = !this.state.isRunning;
187
-
188
- if (this.state.isRunning) {
189
- this.startAutoIncrement();
190
- }
191
- };
192
-
193
- private startAutoIncrement() {
194
- const interval = setInterval(() => {
195
- if (!this.state.isRunning) {
196
- clearInterval(interval);
197
- return;
198
- }
199
-
200
- this.increment();
201
-
202
- // 演示批量更新:这些变化会被合并为一次重渲染
203
- if (this.state.count % 5 === 0) {
204
- this.state.message = `Count reached ${this.state.count}!`;
205
- }
206
- }, 200);
207
- }
208
-
209
- private addToHistory(value: number) {
210
- this.history = [...this.history, value];
211
- }
212
-
213
- private clearHistory = () => {
214
- this.history = [];
215
- };
216
-
217
- protected onConnected(): void {
218
- logger.info("ReactiveCounter connected to DOM");
219
-
220
- // 组件挂载时显示欢迎消息
221
- setTimeout(() => {
222
- this.state.message = "Ready to count! 🚀";
223
- }, 500);
224
- }
225
-
226
- protected onDisconnected(): void {
227
- logger.info("ReactiveCounter disconnected from DOM");
228
- // 清理定时器等资源
229
- this.state.isRunning = false;
230
- }
231
- }
@@ -1,59 +0,0 @@
1
- /** @jsxImportSource @wsxjs/wsx-core */
2
- /**
3
- * 简单的响应式演示组件
4
- * 展示 WSX 响应式状态系统的基本功能
5
- * 使用 @state 装饰器自动初始化响应式状态
6
- */
7
-
8
- import { WebComponent, state, autoRegister, createLogger } from "@wsxjs/wsx-core";
9
-
10
- const logger = createLogger("SimpleReactiveDemo");
11
-
12
- @autoRegister({ tagName: "simple-reactive-demo" })
13
- export default class SimpleReactiveDemo extends WebComponent {
14
- // 使用 @state 装饰器 - 自动初始化为响应式状态
15
- @state private state = {
16
- count: 0,
17
- message: "Click the button!",
18
- };
19
-
20
- constructor() {
21
- super();
22
- logger.info("SimpleReactiveDemo initialized");
23
- }
24
-
25
- render() {
26
- return (
27
- <div style="padding: 20px; border: 1px solid #ccc; border-radius: 8px; margin: 20px;">
28
- <h3>📱 Simple Reactive Demo</h3>
29
- <p>{this.state.message}</p>
30
- <div style="font-size: 24px; margin: 16px 0;">
31
- Count: <strong>{this.state.count}</strong>
32
- </div>
33
- <div>
34
- <button onClick={this.increment} style="margin-right: 8px; padding: 8px 16px;">
35
- + Increment
36
- </button>
37
- <button onClick={this.reset} style="padding: 8px 16px;">
38
- 🔄 Reset
39
- </button>
40
- </div>
41
- <div style="margin-top: 16px; font-size: 12px; color: #666;">
42
- 💡 State changes automatically trigger re-renders!
43
- </div>
44
- </div>
45
- );
46
- }
47
-
48
- private increment = () => {
49
- this.state.count++;
50
- this.state.message = `Clicked ${this.state.count} time${this.state.count === 1 ? "" : "s"}!`;
51
- // 注意:不需要手动调用 this.rerender()!
52
- };
53
-
54
- private reset = () => {
55
- this.state.count = 0;
56
- this.state.message = "Reset! Click again!";
57
- // 注意:这里也不需要手动调用 this.rerender()!
58
- };
59
- }