@sun-panel/micro-app 1.0.6 → 1.0.7

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/README.md CHANGED
@@ -7,7 +7,6 @@ Sun Panel 微应用组件 - 基于 LitElement 的微应用开发框架,提供
7
7
  `@sun-panel/micro-app` 是一个用于开发 Sun Panel 微应用的 JavaScript 组件库,提供了:
8
8
 
9
9
  - 基于原生 Web Components 的基础组件类
10
- - 内置的事件绑定和验证功能
11
10
  - TypeScript 类型定义支持
12
11
  - 预设的卡片和页面组件基类
13
12
  - 与 Lit 框架兼容的开发体验
@@ -20,279 +19,4 @@ npm install @sun-panel/micro-app
20
19
 
21
20
  ## 快速开始
22
21
 
23
- ### 创建卡片组件
24
-
25
- ```javascript
26
- import { SunPanelCardElement } from '@sun-panel/micro-app';
27
-
28
- class MyCard extends SunPanelCardElement {
29
- constructor() {
30
- super();
31
- this.title = 'My Card';
32
- this.count = 0;
33
- }
34
-
35
- render() {
36
- return `
37
- <style>
38
- :host {
39
- display: block;
40
- padding: 16px;
41
- border: 1px solid #ccc;
42
- }
43
- </style>
44
- <h3>${this.title}</h3>
45
- <p>Count: ${this.count}</p>
46
- <button onclick="this.increment()">Increment</button>
47
- `;
48
- }
49
-
50
- increment() {
51
- this.count++;
52
- this.update();
53
- }
54
- }
55
-
56
- // 定义自定义元素
57
- customElements.define('my-card', MyCard);
58
- ```
59
-
60
- ### 创建页面组件
61
-
62
- ```javascript
63
- import { SunPanelPageElement } from '@sun-panel/micro-app';
64
-
65
- class MyPage extends SunPanelPageElement {
66
- constructor() {
67
- super();
68
- this.message = 'Hello World';
69
- }
70
-
71
- render() {
72
- return `
73
- <style>
74
- :host {
75
- display: block;
76
- padding: 20px;
77
- }
78
- </style>
79
- <h1>${this.pageTitle}</h1>
80
- <p>${this.message}</p>
81
- `;
82
- }
83
- }
84
-
85
- // 定义自定义元素
86
- customElements.define('my-page', MyPage);
87
- ```
88
-
89
- ### 使用验证功能
90
-
91
- ```typescript
92
- import { Validator, FormValidator } from '@sun-panel/micro-app';
93
-
94
- // 验证单个字段
95
- const rules = {
96
- required: true,
97
- type: 'string',
98
- minLength: 3,
99
- maxLength: 20
100
- };
101
-
102
- const errors = await Validator.validateField('test', rules, 'username');
103
- if (errors.length > 0) {
104
- console.log('Validation errors:', errors);
105
- }
106
-
107
- // 验证对象
108
- const formRules = {
109
- username: {
110
- required: true,
111
- type: 'string',
112
- minLength: 3
113
- },
114
- email: {
115
- required: true,
116
- type: 'email'
117
- }
118
- };
119
-
120
- const formData = {
121
- username: 'test',
122
- email: 'test@example.com'
123
- };
124
-
125
- const formValidator = new FormValidator(formRules);
126
- await formValidator.validateOrThrow(formData); // 抛出验证错误或无错误
127
- ```
128
-
129
- ## 核心组件
130
-
131
- ### SunPanelElement
132
-
133
- 基础元素类,提供微应用的基本能力:
134
-
135
- - 基于原生 Web Components 标准
136
- - 内置影子 DOM 管理
137
- - 属性和生命周期管理
138
- - 事件派发机制
139
-
140
- ### SunPanelCardElement
141
-
142
- 卡片元素基类,适用于微应用中的卡片组件:
143
-
144
- - 支持卡片大小配置
145
- - 支持卡片标题
146
- - 内置卡片信息处理
147
- - 预设卡片样式
148
-
149
- ### SunPanelPageElement
150
-
151
- 页面元素基类,适用于微应用中的页面组件:
152
-
153
- - 支持页面标题和描述
154
- - 内置页面生命周期管理
155
- - 预设页面布局
156
-
157
- ## API
158
-
159
- ### 元素生命周期
160
-
161
- - `connectedCallback()` - 元素插入 DOM 时调用
162
- - `disconnectedCallback()` - 元素从 DOM 移除时调用
163
- - `attributeChangedCallback()` - 属性变化时调用
164
-
165
- ### 实用工具
166
-
167
- - `Validator` - 验证工具类
168
- - `FormValidator` - 表单验证器
169
- - `ValidationError` - 验证错误类
170
-
171
- ## 构建
172
-
173
- ```bash
174
- # 复制源文件到发布目录
175
- npm run build
176
- ```
177
-
178
- ## 开发
179
-
180
- ### 开发测试环境
181
-
182
- ```bash
183
- # 启动开发服务器(带热重载)
184
- ✓ Rollup 正在监听文件变化
185
- ✓ 开发服务器运行在: http://localhost:3000
186
- ✓ LiveReload 已启用
187
- ✓ 成功构建: dev/bundle.js (91ms)
188
-
189
- ```
190
-
191
- 这将:
192
- - 启动 Rollup watch 模式监听文件变化
193
- - 自动启动开发服务器(http://localhost:3000)
194
- - 自动在浏览器中打开测试页面
195
- - 支持源码修改后自动重新构建和热重载
196
-
197
- ### 测试环境功能
198
-
199
- 开发测试环境包含:
200
- - **卡片组件测试**:展示不同主题和大小的卡片
201
- - **页面组件测试**:演示页面组件的功能
202
- - **验证功能测试**:测试字段和表单验证
203
- - **实时预览**:修改源代码后自动刷新
204
-
205
- ### 修改代码后
206
-
207
- 1. 修改 `src/` 目录下的源代码
208
- 2. Rollup 会自动重新构建 `dev/bundle.js`
209
- 3. 浏览器会自动刷新
210
- 4. 立即查看修改效果
211
-
212
- ### 构建生产版本
213
-
214
- ```bash
215
- # 构建生产版本
216
- npm run build
217
- ```
218
-
219
- ## 开发模式说明
220
-
221
- 此库采用 TypeScript 定义文件的开发模式:
222
-
223
- - 使用者可以选择使用 JavaScript 或 TypeScript 方式导入和使用组件
224
-
225
- ## 开发时链接模块(开发者指南)
226
-
227
- 如果你正在开发基于 `@sun-panel/micro-app` 的微应用,并且希望在开发时获得最新的类型提示,可以使用 npm link 方式链接到本地的开发版本:
228
-
229
- ### 在微应用项目中链接开发版本
230
-
231
- 假设你有以下目录结构:
232
- ```
233
- sun-panel-app/
234
- ├── sun-panel-micro-app/ # 正在开发的模块
235
- └── sun-panel-micro-app-hslr-demo-app/ # 微应用项目
236
- ```
237
-
238
- **步骤 1:在 sun-panel-micro-app 目录创建全局链接**
239
-
240
- ```bash
241
- cd sun-panel-micro-app
242
- npm link
243
- ```
244
-
245
- **步骤 2:在微应用项目目录链接到全局包**
246
-
247
- ```bash
248
- cd sun-panel-micro-app-hslr-demo-app
249
- npm link @sun-panel/micro-app
250
- ```
251
-
252
- **步骤 3:重新加载 VSCode**
253
-
254
- 按 `Cmd+Shift+P`,输入 "Developer: Reload Window" 并回车。
255
-
256
- ### 配置 jsconfig.json
257
-
258
- 在微应用项目根目录创建 `jsconfig.json` 文件:
259
-
260
- ```json
261
- {
262
- "compilerOptions": {
263
- "baseUrl": ".",
264
- "moduleResolution": "node",
265
- "checkJs": true
266
- },
267
- "include": ["src/**/*", "**/*.js"],
268
- "exclude": ["node_modules", "dist"]
269
- }
270
- ```
271
-
272
- ### 效果
273
-
274
- - ✅ 编辑器会显示来自 `sun-panel-micro-app/src` 的最新类型定义
275
- - ✅ 修改类型定义后无需重新发布,编辑器会自动更新提示
276
- - ✅ 运行时代码通过 vite alias 引用开发目录的代码
277
- - ✅ 类型提示通过 npm link 引用开发目录的类型定义
278
-
279
- ### 解除链接
280
-
281
- 如果要恢复使用 npm 发布的版本:
282
-
283
- ```bash
284
- cd sun-panel-micro-app-hslr-demo-app
285
- npm unlink @sun-panel/micro-app
286
- ```
287
-
288
- 然后重新加载 VSCode 即可。
289
-
290
- ## 类型定义开源
291
-
292
- 本项目的所有类型定义文件(以 `.d.ts` 结尾的文件)采用 MIT 开源协议发布,允许在任何项目中自由使用。
293
-
294
- 详细信息请参阅 [TYPES_LICENSE.md](TYPES_LICENSE.md) 文件。
295
-
296
- ## 许可证
297
-
298
- MIT
22
+ 参阅:[官方微应用开发文档](https://doc.sun-panel.top/v2/zh_cn/micro_app_dev/)
@@ -1,7 +1,6 @@
1
1
  import { SunPanelElement } from './SunPanelElement';
2
2
  import { TemplateResult, PropertyValueMap } from 'lit';
3
- import { SpContextPage, NetworkMode } from './types/common';
4
- import { PageInitializedParam } from './types/api';
3
+ import { SpContextPage, NetworkMode, PageInitializedParam } from './types/common';
5
4
  /**
6
5
  * Sun Panel 页面元素基类
7
6
  * 用于开发微应用中的页面组件,以窗口的形式加载
@@ -1 +1 @@
1
- {"version":3,"file":"SunPanelPageElement.d.ts","sourceRoot":"","sources":["../src/SunPanelPageElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAQ,cAAc,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAwB,MAAM,gBAAgB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAe,MAAM,aAAa,CAAC;AAGhE;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;IAEtD,MAAM,CAAC,UAAU;;;;;MAGf;IAEF,KAAK,EAAE,aAAa,CAAC;;IAmBrB;;;;OAIG;IACH,aAAa,CAAC,cAAc,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI;IAa3D;;OAEG;IACH;;;OAGG;IACH,YAAY,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAK/E;;OAEG;IACH,OAAO,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAwB1E,WAAW,IAAI,IAAI;IAKnB;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAIjD;;;OAGG;IACH,eAAe,IAAI,IAAI;IAIvB;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI;IAI9D;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAIhE;;;OAGG;IACH,oBAAoB,CAAC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,GAAG,IAAI;IAInF;;OAEG;IACH,MAAM,IAAI,cAAc;CAIzB"}
1
+ {"version":3,"file":"SunPanelPageElement.d.ts","sourceRoot":"","sources":["../src/SunPanelPageElement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAQ,cAAc,EAAE,gBAAgB,EAAE,MAAM,KAAK,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,WAAW,EAAwB,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAIxG;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;IAEtD,MAAM,CAAC,UAAU;;;;;MAGf;IAEF,KAAK,EAAE,aAAa,CAAC;;IAmBrB;;;;OAIG;IACH,aAAa,CAAC,cAAc,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI;IAa3D;;OAEG;IACH;;;OAGG;IACH,YAAY,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAK/E;;OAEG;IACH,OAAO,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAwB1E,WAAW,IAAI,IAAI;IAKnB;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI;IAIjD;;;OAGG;IACH,eAAe,IAAI,IAAI;IAIvB;;;OAGG;IACH,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI;IAI9D;;;OAGG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAIhE;;;OAGG;IACH,oBAAoB,CAAC,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,GAAG,IAAI;IAInF;;OAEG;IACH,MAAM,IAAI,cAAc;CAIzB"}
@@ -20,5 +20,5 @@ const b=globalThis,E=t=>t,C=b.trustedTypes,w=C?C.createPolicy("lit-html",{create
20
20
  * @license
21
21
  * Copyright 2017 Google LLC
22
22
  * SPDX-License-Identifier: BSD-3-Clause
23
- */class ot extends v{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=((t,e,s)=>{const i=s?.renderBefore??e;let n=i._$litPart$;if(void 0===n){const t=s?.renderBefore??null;i._$litPart$=n=new X(e.insertBefore(O(),t),t,void 0,s??{})}return n._$AI(t),n})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return B}}ot._$litElement$=!0,ot.finalized=!0,rt.litElementHydrateSupport?.({LitElement:ot});const at=rt.litElementPolyfillSupport;at?.({LitElement:ot}),(rt.litElementVersions??=[]).push("4.2.2");class ht extends ot{constructor(){super(),this._initialized=!1,this._eventListeners=new Map}initializeMicroApp(){this._initialized||(this._setupEventListeners(),this._initialized=!0)}connectedCallback(){super.connectedCallback(),this.initializeMicroApp(),this.onConnected()}disconnectedCallback(){super.disconnectedCallback(),this._cleanupEventListeners(),this.onDisconnected()}attributeChangedCallback(t,e,s){super.attributeChangedCallback(t,e,s),this.onAttributeChanged(t,e,s)}_setupEventListeners(){}_cleanupEventListeners(){const t=Array.from(this._eventListeners.entries());for(const[e,s]of t)s.forEach(t=>{window.removeEventListener(e,t)});this._eventListeners.clear()}addEventListener(t,e,s){super.addEventListener(t,e,s)}dispatchCustomEvent(t,e){const s=new CustomEvent(t,{bubbles:!0,composed:!0,detail:e});this.dispatchEvent(s)}onConnected(){}onDisconnected(){}onAttributeChanged(t,e,s){}render(){return V``}}class lt extends ht{constructor(){super(),this.spCtx={api:{},darkMode:!1,language:"zh-CN",networkMode:"wan",staticPath:"",role:0,widgetInfo:{}}}updateContext(t){if(!t||"object"!=typeof t)return;const e=Object.fromEntries(Object.entries(t).filter(([t,e])=>void 0!==e));this.spCtx={...this.spCtx,...e}}firstUpdated(t){super.firstUpdated?.(t),this.onFirstRendered()}updated(t){if(super.updated(t),t.has("spCtx")){const e=t.get("spCtx")||{},s=this.spCtx;s.widgetInfo!==e.widgetInfo&&this.onWidgetInfoChanged(s.widgetInfo,e.widgetInfo),s.darkMode!==e.darkMode&&this.onDarkModeChanged(s.darkMode,e.darkMode),s.language!==e.language&&this.onLanguageChanged(s.language,e.language),s.networkMode!==e.networkMode&&this.onNetworkModeChanged(s.networkMode,e.networkMode)}}onConnected(){super.onConnected(),this.onInitialized()}onInitialized(){}onFirstRendered(){}onDarkModeChanged(t,e){}onLanguageChanged(t,e){}onNetworkModeChanged(t,e){}onWidgetInfoChanged(t,e){}render(){return V``}}lt.properties={spCtx:{type:Object,attribute:!1}};class dt extends ht{constructor(){super(),this.spCtx={api:{},darkMode:!1,language:"zh-CN",networkMode:"wan",staticPath:"",role:0,background:"",widgetInfo:{},customParam:{}}}updateContext(t){if(!t||"object"!=typeof t)return;const e=Object.fromEntries(Object.entries(t).filter(([t,e])=>void 0!==e));this.spCtx={...this.spCtx,...e}}firstUpdated(t){super.firstUpdated?.(t),this.onFirstRendered()}updated(t){if(super.updated(t),t.has("spCtx")){const e=t.get("spCtx")||{},s=this.spCtx;s.darkMode!==e.darkMode&&this.onDarkModeChanged(s.darkMode,e.darkMode),s.language!==e.language&&this.onLanguageChanged(s.language,e.language),s.networkMode!==e.networkMode&&this.onNetworkModeChanged(s.networkMode,e.networkMode)}}onConnected(){super.onConnected(),this.onInitialized({widgetInfo:this.spCtx.widgetInfo,customParam:this.spCtx.customParam})}onInitialized(t){}onFirstRendered(){}onDarkModeChanged(t,e){}onLanguageChanged(t,e){}onNetworkModeChanged(t,e){}render(){return V``}}dt.properties={spCtx:{type:Object,attribute:!1}};class ct extends Error{constructor(t){super(`Validation failed: ${t.map(t=>t.message).join(", ")}`),this.name="ValidationError",this.errors=t}}class pt{static async validateField(t,e,s="field"){const i=[];if(e.required&&(null==t||""===t))return i.push({field:s,message:e.message||`${s} is required`,value:t}),i;if(null==t||""===t)return i;if(e.type){let n=!1;switch(e.type){case"string":n="string"==typeof t;break;case"number":n="number"==typeof t&&!isNaN(t);break;case"boolean":n="boolean"==typeof t;break;case"object":n="object"==typeof t&&null!==t&&!Array.isArray(t);break;case"array":n=Array.isArray(t);break;case"date":n=t instanceof Date||!isNaN(Date.parse(t));break;case"email":n="string"==typeof t&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);break;case"url":try{new URL(t),n=!0}catch{n=!1}break;default:n=!0}n||i.push({field:s,message:e.message||`${s} must be of type ${e.type}`,value:t})}if(void 0!==e.minLength&&"string"==typeof t&&t.length<e.minLength&&i.push({field:s,message:e.message||`${s} must be at least ${e.minLength} characters`,value:t}),void 0!==e.maxLength&&"string"==typeof t&&t.length>e.maxLength&&i.push({field:s,message:e.message||`${s} must be no more than ${e.maxLength} characters`,value:t}),void 0!==e.min&&"number"==typeof t&&t<e.min&&i.push({field:s,message:e.message||`${s} must be at least ${e.min}`,value:t}),void 0!==e.max&&"number"==typeof t&&t>e.max&&i.push({field:s,message:e.message||`${s} must be no more than ${e.max}`,value:t}),e.pattern&&"string"==typeof t&&!e.pattern.test(t)&&i.push({field:s,message:e.message||`${s} format is invalid`,value:t}),e.validator)try{const n=await Promise.resolve(e.validator(t));"string"==typeof n?i.push({field:s,message:n,value:t}):!1===n&&i.push({field:s,message:e.message||`${s} is invalid`,value:t})}catch(n){i.push({field:s,message:e.message||`Validation failed for ${s}: ${n instanceof Error?n.message:String(n)}`,value:t})}return i}static async validateObject(t,e){const s=[];for(const i of Object.keys(e)){const n=e[i],r=t[i],o=await this.validateField(r,n,i);s.push(...o)}return s}static async validateArray(t,e){if(!Array.isArray(t))return[{field:"array",message:"Value must be an array",value:t}];const s=[];if(void 0!==e.min&&t.length<e.min&&s.push({field:"array",message:e.message||`Array must have at least ${e.min} items`,value:t}),void 0!==e.max&&t.length>e.max&&s.push({field:"array",message:e.message||`Array must have no more than ${e.max} items`,value:t}),e.validator)for(let i=0;i<t.length;i++){const n=t[i],r=await this.validateField(n,e,`array[${i}]`);s.push(...r)}return s}}t.FormValidator=class{constructor(t){this.rules=t}async validate(t){return await pt.validateObject(t,this.rules)}async validateOrThrow(t){const e=await this.validate(t);if(e.length>0)throw new ct(e)}},t.SunPanelElement=ht,t.SunPanelPageElement=dt,t.SunPanelWidgetElement=lt,t.VERSION='"1.0.6"',t.ValidationError=ct,t.Validator=pt}(this.SunPanelMicroApp=this.SunPanelMicroApp||{});
23
+ */class ot extends v{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const e=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=((t,e,s)=>{const i=s?.renderBefore??e;let n=i._$litPart$;if(void 0===n){const t=s?.renderBefore??null;i._$litPart$=n=new X(e.insertBefore(O(),t),t,void 0,s??{})}return n._$AI(t),n})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return B}}ot._$litElement$=!0,ot.finalized=!0,rt.litElementHydrateSupport?.({LitElement:ot});const at=rt.litElementPolyfillSupport;at?.({LitElement:ot}),(rt.litElementVersions??=[]).push("4.2.2");class ht extends ot{constructor(){super(),this._initialized=!1,this._eventListeners=new Map}initializeMicroApp(){this._initialized||(this._setupEventListeners(),this._initialized=!0)}connectedCallback(){super.connectedCallback(),this.initializeMicroApp(),this.onConnected()}disconnectedCallback(){super.disconnectedCallback(),this._cleanupEventListeners(),this.onDisconnected()}attributeChangedCallback(t,e,s){super.attributeChangedCallback(t,e,s),this.onAttributeChanged(t,e,s)}_setupEventListeners(){}_cleanupEventListeners(){const t=Array.from(this._eventListeners.entries());for(const[e,s]of t)s.forEach(t=>{window.removeEventListener(e,t)});this._eventListeners.clear()}addEventListener(t,e,s){super.addEventListener(t,e,s)}dispatchCustomEvent(t,e){const s=new CustomEvent(t,{bubbles:!0,composed:!0,detail:e});this.dispatchEvent(s)}onConnected(){}onDisconnected(){}onAttributeChanged(t,e,s){}render(){return V``}}class lt extends ht{constructor(){super(),this.spCtx={api:{},darkMode:!1,language:"zh-CN",networkMode:"wan",staticPath:"",role:0,widgetInfo:{}}}updateContext(t){if(!t||"object"!=typeof t)return;const e=Object.fromEntries(Object.entries(t).filter(([t,e])=>void 0!==e));this.spCtx={...this.spCtx,...e}}firstUpdated(t){super.firstUpdated?.(t),this.onFirstRendered()}updated(t){if(super.updated(t),t.has("spCtx")){const e=t.get("spCtx")||{},s=this.spCtx;s.widgetInfo!==e.widgetInfo&&this.onWidgetInfoChanged(s.widgetInfo,e.widgetInfo),s.darkMode!==e.darkMode&&this.onDarkModeChanged(s.darkMode,e.darkMode),s.language!==e.language&&this.onLanguageChanged(s.language,e.language),s.networkMode!==e.networkMode&&this.onNetworkModeChanged(s.networkMode,e.networkMode)}}onConnected(){super.onConnected(),this.onInitialized()}onInitialized(){}onFirstRendered(){}onDarkModeChanged(t,e){}onLanguageChanged(t,e){}onNetworkModeChanged(t,e){}onWidgetInfoChanged(t,e){}render(){return V``}}lt.properties={spCtx:{type:Object,attribute:!1}};class dt extends ht{constructor(){super(),this.spCtx={api:{},darkMode:!1,language:"zh-CN",networkMode:"wan",staticPath:"",role:0,background:"",widgetInfo:{},customParam:{}}}updateContext(t){if(!t||"object"!=typeof t)return;const e=Object.fromEntries(Object.entries(t).filter(([t,e])=>void 0!==e));this.spCtx={...this.spCtx,...e}}firstUpdated(t){super.firstUpdated?.(t),this.onFirstRendered()}updated(t){if(super.updated(t),t.has("spCtx")){const e=t.get("spCtx")||{},s=this.spCtx;s.darkMode!==e.darkMode&&this.onDarkModeChanged(s.darkMode,e.darkMode),s.language!==e.language&&this.onLanguageChanged(s.language,e.language),s.networkMode!==e.networkMode&&this.onNetworkModeChanged(s.networkMode,e.networkMode)}}onConnected(){super.onConnected(),this.onInitialized({widgetInfo:this.spCtx.widgetInfo,customParam:this.spCtx.customParam})}onInitialized(t){}onFirstRendered(){}onDarkModeChanged(t,e){}onLanguageChanged(t,e){}onNetworkModeChanged(t,e){}render(){return V``}}dt.properties={spCtx:{type:Object,attribute:!1}};class ct extends Error{constructor(t){super(`Validation failed: ${t.map(t=>t.message).join(", ")}`),this.name="ValidationError",this.errors=t}}class pt{static async validateField(t,e,s="field"){const i=[];if(e.required&&(null==t||""===t))return i.push({field:s,message:e.message||`${s} is required`,value:t}),i;if(null==t||""===t)return i;if(e.type){let n=!1;switch(e.type){case"string":n="string"==typeof t;break;case"number":n="number"==typeof t&&!isNaN(t);break;case"boolean":n="boolean"==typeof t;break;case"object":n="object"==typeof t&&null!==t&&!Array.isArray(t);break;case"array":n=Array.isArray(t);break;case"date":n=t instanceof Date||!isNaN(Date.parse(t));break;case"email":n="string"==typeof t&&/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);break;case"url":try{new URL(t),n=!0}catch{n=!1}break;default:n=!0}n||i.push({field:s,message:e.message||`${s} must be of type ${e.type}`,value:t})}if(void 0!==e.minLength&&"string"==typeof t&&t.length<e.minLength&&i.push({field:s,message:e.message||`${s} must be at least ${e.minLength} characters`,value:t}),void 0!==e.maxLength&&"string"==typeof t&&t.length>e.maxLength&&i.push({field:s,message:e.message||`${s} must be no more than ${e.maxLength} characters`,value:t}),void 0!==e.min&&"number"==typeof t&&t<e.min&&i.push({field:s,message:e.message||`${s} must be at least ${e.min}`,value:t}),void 0!==e.max&&"number"==typeof t&&t>e.max&&i.push({field:s,message:e.message||`${s} must be no more than ${e.max}`,value:t}),e.pattern&&"string"==typeof t&&!e.pattern.test(t)&&i.push({field:s,message:e.message||`${s} format is invalid`,value:t}),e.validator)try{const n=await Promise.resolve(e.validator(t));"string"==typeof n?i.push({field:s,message:n,value:t}):!1===n&&i.push({field:s,message:e.message||`${s} is invalid`,value:t})}catch(n){i.push({field:s,message:e.message||`Validation failed for ${s}: ${n instanceof Error?n.message:String(n)}`,value:t})}return i}static async validateObject(t,e){const s=[];for(const i of Object.keys(e)){const n=e[i],r=t[i],o=await this.validateField(r,n,i);s.push(...o)}return s}static async validateArray(t,e){if(!Array.isArray(t))return[{field:"array",message:"Value must be an array",value:t}];const s=[];if(void 0!==e.min&&t.length<e.min&&s.push({field:"array",message:e.message||`Array must have at least ${e.min} items`,value:t}),void 0!==e.max&&t.length>e.max&&s.push({field:"array",message:e.message||`Array must have no more than ${e.max} items`,value:t}),e.validator)for(let i=0;i<t.length;i++){const n=t[i],r=await this.validateField(n,e,`array[${i}]`);s.push(...r)}return s}}t.FormValidator=class{constructor(t){this.rules=t}async validate(t){return await pt.validateObject(t,this.rules)}async validateOrThrow(t){const e=await this.validate(t);if(e.length>0)throw new ct(e)}},t.SunPanelElement=ht,t.SunPanelPageElement=dt,t.SunPanelWidgetElement=lt,t.VERSION='"1.0.7"',t.ValidationError=ct,t.Validator=pt}(this.SunPanelMicroApp=this.SunPanelMicroApp||{});
24
24
  //# sourceMappingURL=index.bundle.js.map