feat: align with base project's No ESM design and register global Kanban component (by AI)
This commit is contained in:
parent
66f24fdbe0
commit
f6983f7224
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
test-results/
|
||||||
|
playwright-report/
|
||||||
|
.DS_Store
|
||||||
@ -1,4 +1,9 @@
|
|||||||
# @web/kanban 更新日志
|
# @apigo.cc/kanban 更新日志
|
||||||
|
|
||||||
|
## v1.0.2 (2026-06-12)
|
||||||
|
- **架构对齐**: 遵循 `base` 包新设计,彻底消灭用户侧 ESM 强依赖。
|
||||||
|
- **组件注册**: 支持 `<Kanban>` 全局组件声明式用法(兼容 `$state` 框架)。
|
||||||
|
- **构建优化**: 产物调整为纯 UMD 模式,通过 `globalThis.Kanban` 暴露 API。
|
||||||
|
|
||||||
## v1.0.0 (2026-05-29)
|
## v1.0.0 (2026-05-29)
|
||||||
- **Feat**: 初始化看板引擎,支持多列渲染。
|
- **Feat**: 初始化看板引擎,支持多列渲染。
|
||||||
|
|||||||
99
README.md
99
README.md
@ -1,78 +1,53 @@
|
|||||||
# @web/kanban
|
# @apigo.cc/kanban API 手册
|
||||||
|
|
||||||
原生 ESM 驱动的极简看板引擎,专注于无状态渲染与高性能拖拽。
|
原生 Web Component 编写的轻量级看板组件。支持响应式数据绑定与自动拖拽排序。
|
||||||
|
|
||||||
## 核心特性
|
---
|
||||||
- **零依赖**: 仅使用原生 Web Components 与 Drag & Drop API。
|
|
||||||
- **双轨分发**: 提供源码版 `kanban.js` 与压缩版 `kanban.min.js`。
|
|
||||||
- **高性能**: 支持数百个看板项的丝滑交互。
|
|
||||||
|
|
||||||
## 快速上手
|
## 1. 引入方式 (UMD 优先)
|
||||||
|
|
||||||
### 1. 引入模块
|
在 HTML 中引入脚本即刻注册 `<web-kanban>` 自定义标签。
|
||||||
使用 `loader.js` 或直接通过 `importmap` 引入:
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script type="importmap">
|
<script src="https://cdn.jsdelivr.net/npm/@apigo.cc/kanban@1.0.1/dist/kanban.min.js"></script>
|
||||||
{
|
|
||||||
"imports": {
|
<script>
|
||||||
"@web/kanban": "./dist/kanban.js"
|
// 直接操作全局 Kanban 类或 DOM 元素
|
||||||
}
|
console.log(Kanban);
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="module">
|
|
||||||
import '@web/kanban';
|
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 使用组件
|
---
|
||||||
|
|
||||||
|
## 2. 核心用法
|
||||||
|
|
||||||
|
### 组件化用法 (推荐)
|
||||||
|
直接在 HTML 中使用 `<Kanban>` 标签,通过 `state` 进行数据绑定。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<web-kanban id="my-kanban"></web-kanban>
|
<div $data="{
|
||||||
|
myBoard: [
|
||||||
<script type="module">
|
{ id: 'todo', title: '待办', items: [{ id: '1', content: '任务 1' }] }
|
||||||
const kanban = document.querySelector('#my-kanban');
|
]
|
||||||
|
}">
|
||||||
// 注入数据
|
<Kanban $.state.data="myBoard"></Kanban>
|
||||||
kanban.data = [
|
</div>
|
||||||
{
|
|
||||||
id: 'todo',
|
|
||||||
title: '待处理',
|
|
||||||
items: [
|
|
||||||
{ id: '1', content: '任务一' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'done',
|
|
||||||
title: '已完成',
|
|
||||||
items: []
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 监听更新
|
|
||||||
kanban.addEventListener('@update', (e) => {
|
|
||||||
console.log('最新数据:', e.detail);
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## API 参考
|
### JS 直接调用
|
||||||
|
...
|
||||||
|
---
|
||||||
|
|
||||||
### 属性 (Properties)
|
## 3. API 参考
|
||||||
- `data`: `Array<Column>` - 获取或设置看板数据。
|
|
||||||
|
|
||||||
### 数据结构 (Types)
|
### 属性
|
||||||
```typescript
|
- **`.data`**: 设置或获取看板数组。
|
||||||
interface Column {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
items: Item[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Item {
|
### 事件
|
||||||
id: string;
|
- **`@update`**: 拖拽结束且位置变动时触发,`detail` 为全量新数据。
|
||||||
content: string;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 事件 (Events)
|
---
|
||||||
- `@update`: 当看板项位置发生变化时触发。`event.detail` 包含完整的 `Column[]` 数据。
|
|
||||||
|
## 开发者提示 (AI 必读)
|
||||||
|
1. **样式隔离**: 组件使用 Shadow DOM,外部 CSS 无法影响内部。
|
||||||
|
2. **全局变量**: UMD 模式下,`Kanban` 类自动挂载到 `window`。
|
||||||
|
|||||||
2
TEST.md
2
TEST.md
@ -1,4 +1,4 @@
|
|||||||
# @web/kanban 测试报告
|
# @apigo.cc/kanban 测试报告
|
||||||
|
|
||||||
## 基准性能 (Benchmark)
|
## 基准性能 (Benchmark)
|
||||||
- **环境**: Desktop Chrome (Playwright)
|
- **环境**: Desktop Chrome (Playwright)
|
||||||
|
|||||||
164
dist/kanban.js
vendored
164
dist/kanban.js
vendored
@ -1,4 +1,7 @@
|
|||||||
var __typeError = (msg) => {
|
(function(global, factory) {
|
||||||
|
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.ApigoKanban = {}));
|
||||||
|
})(this, function(exports2) {
|
||||||
|
"use strict";var __typeError = (msg) => {
|
||||||
throw TypeError(msg);
|
throw TypeError(msg);
|
||||||
};
|
};
|
||||||
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
||||||
@ -6,29 +9,30 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|||||||
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
||||||
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
||||||
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
||||||
var _data, _Kanban_instances, render_fn, initDragAndDrop_fn, moveItem_fn;
|
|
||||||
class Kanban extends HTMLElement {
|
var _data, _Kanban_instances, render_fn, initDragAndDrop_fn, moveItem_fn;
|
||||||
constructor() {
|
class Kanban extends HTMLElement {
|
||||||
super();
|
constructor() {
|
||||||
__privateAdd(this, _Kanban_instances);
|
super();
|
||||||
__privateAdd(this, _data, []);
|
__privateAdd(this, _Kanban_instances);
|
||||||
this.attachShadow({ mode: "open" });
|
__privateAdd(this, _data, []);
|
||||||
|
this.attachShadow({ mode: "open" });
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
||||||
|
}
|
||||||
|
get data() {
|
||||||
|
return __privateGet(this, _data);
|
||||||
|
}
|
||||||
|
set data(value) {
|
||||||
|
__privateSet(this, _data, value);
|
||||||
|
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
connectedCallback() {
|
_data = new WeakMap();
|
||||||
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
_Kanban_instances = new WeakSet();
|
||||||
}
|
render_fn = function() {
|
||||||
get data() {
|
const style = `
|
||||||
return __privateGet(this, _data);
|
|
||||||
}
|
|
||||||
set data(value) {
|
|
||||||
__privateSet(this, _data, value);
|
|
||||||
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_data = new WeakMap();
|
|
||||||
_Kanban_instances = new WeakSet();
|
|
||||||
render_fn = function() {
|
|
||||||
const style = `
|
|
||||||
:host {
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
@ -75,7 +79,7 @@ render_fn = function() {
|
|||||||
background: rgba(0,0,0,0.05);
|
background: rgba(0,0,0,0.05);
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
this.shadowRoot.innerHTML = `
|
this.shadowRoot.innerHTML = `
|
||||||
<style>${style}</style>
|
<style>${style}</style>
|
||||||
${__privateGet(this, _data).map((col) => `
|
${__privateGet(this, _data).map((col) => `
|
||||||
<div class="column" data-id="${col.id}">
|
<div class="column" data-id="${col.id}">
|
||||||
@ -92,54 +96,70 @@ render_fn = function() {
|
|||||||
</div>
|
</div>
|
||||||
`).join("")}
|
`).join("")}
|
||||||
`;
|
`;
|
||||||
__privateMethod(this, _Kanban_instances, initDragAndDrop_fn).call(this);
|
__privateMethod(this, _Kanban_instances, initDragAndDrop_fn).call(this);
|
||||||
};
|
};
|
||||||
initDragAndDrop_fn = function() {
|
initDragAndDrop_fn = function() {
|
||||||
const items = this.shadowRoot.querySelectorAll(".item");
|
const items = this.shadowRoot.querySelectorAll(".item");
|
||||||
const containers = this.shadowRoot.querySelectorAll(".items-container");
|
const containers = this.shadowRoot.querySelectorAll(".items-container");
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
item.addEventListener("dragstart", (e) => {
|
item.addEventListener("dragstart", (e) => {
|
||||||
item.classList.add("dragging");
|
item.classList.add("dragging");
|
||||||
e.dataTransfer.setData("text/plain", JSON.stringify({
|
e.dataTransfer.setData("text/plain", JSON.stringify({
|
||||||
itemId: item.dataset.id,
|
itemId: item.dataset.id,
|
||||||
fromColumnId: item.dataset.columnId
|
fromColumnId: item.dataset.columnId
|
||||||
}));
|
}));
|
||||||
|
});
|
||||||
|
item.addEventListener("dragend", () => {
|
||||||
|
item.classList.remove("dragging");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
item.addEventListener("dragend", () => {
|
containers.forEach((container) => {
|
||||||
item.classList.remove("dragging");
|
container.addEventListener("dragover", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
container.classList.add("drag-over");
|
||||||
|
});
|
||||||
|
container.addEventListener("dragleave", () => {
|
||||||
|
container.classList.remove("drag-over");
|
||||||
|
});
|
||||||
|
container.addEventListener("drop", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
container.classList.remove("drag-over");
|
||||||
|
const dragData = JSON.parse(e.dataTransfer.getData("text/plain"));
|
||||||
|
__privateMethod(this, _Kanban_instances, moveItem_fn).call(this, dragData.itemId, dragData.fromColumnId, container.dataset.columnId);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
containers.forEach((container) => {
|
moveItem_fn = function(itemId, fromColumnId, toColumnId) {
|
||||||
container.addEventListener("dragover", (e) => {
|
if (fromColumnId === toColumnId) return;
|
||||||
e.preventDefault();
|
const fromCol = __privateGet(this, _data).find((c) => c.id === fromColumnId);
|
||||||
container.classList.add("drag-over");
|
const toCol = __privateGet(this, _data).find((c) => c.id === toColumnId);
|
||||||
|
const itemIndex = fromCol.items.findIndex((i) => i.id === itemId);
|
||||||
|
const [item] = fromCol.items.splice(itemIndex, 1);
|
||||||
|
toCol.items.push(item);
|
||||||
|
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
||||||
|
this.dispatchEvent(new CustomEvent("@update", {
|
||||||
|
detail: __privateGet(this, _data),
|
||||||
|
bubbles: true,
|
||||||
|
composed: true
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
customElements.define("web-kanban", Kanban);
|
||||||
|
if (typeof globalThis !== "undefined" && globalThis.Component) {
|
||||||
|
globalThis.Component.register("Kanban", (container) => {
|
||||||
|
const kanban = document.createElement("web-kanban");
|
||||||
|
container.appendChild(kanban);
|
||||||
|
container.kanbanInstance = kanban;
|
||||||
|
container.state.__watch("data", (val) => kanban.data = val);
|
||||||
|
if (container.state.data) kanban.data = container.state.data;
|
||||||
|
kanban.addEventListener("@update", (e) => {
|
||||||
|
container.state.data = e.detail;
|
||||||
|
container.dispatchEvent(new CustomEvent("update", { detail: e.detail }));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
container.addEventListener("dragleave", () => {
|
}
|
||||||
container.classList.remove("drag-over");
|
if (typeof globalThis !== "undefined") {
|
||||||
});
|
globalThis.Kanban = Kanban;
|
||||||
container.addEventListener("drop", (e) => {
|
}
|
||||||
e.preventDefault();
|
exports2.Kanban = Kanban;
|
||||||
container.classList.remove("drag-over");
|
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
|
||||||
const dragData = JSON.parse(e.dataTransfer.getData("text/plain"));
|
});
|
||||||
__privateMethod(this, _Kanban_instances, moveItem_fn).call(this, dragData.itemId, dragData.fromColumnId, container.dataset.columnId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
moveItem_fn = function(itemId, fromColumnId, toColumnId) {
|
|
||||||
if (fromColumnId === toColumnId) return;
|
|
||||||
const fromCol = __privateGet(this, _data).find((c) => c.id === fromColumnId);
|
|
||||||
const toCol = __privateGet(this, _data).find((c) => c.id === toColumnId);
|
|
||||||
const itemIndex = fromCol.items.findIndex((i) => i.id === itemId);
|
|
||||||
const [item] = fromCol.items.splice(itemIndex, 1);
|
|
||||||
toCol.items.push(item);
|
|
||||||
__privateMethod(this, _Kanban_instances, render_fn).call(this);
|
|
||||||
this.dispatchEvent(new CustomEvent("@update", {
|
|
||||||
detail: __privateGet(this, _data),
|
|
||||||
bubbles: true,
|
|
||||||
composed: true
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
customElements.define("web-kanban", Kanban);
|
|
||||||
export {
|
|
||||||
Kanban
|
|
||||||
};
|
|
||||||
|
|||||||
2
dist/kanban.min.js
vendored
2
dist/kanban.min.js
vendored
@ -1 +1 @@
|
|||||||
var n,t,e,a,i,s=n=>{throw TypeError(n)},d=(n,t,e)=>t.has(n)||s("Cannot "+e),r=(n,t,e)=>(d(n,t,"read from private field"),e?e.call(n):t.get(n)),o=(n,t,e)=>t.has(n)?s("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(n):t.set(n,e),l=(n,t,e)=>(d(n,t,"access private method"),e);class c extends HTMLElement{constructor(){super(),o(this,t),o(this,n,[]),this.attachShadow({mode:"open"})}connectedCallback(){l(this,t,e).call(this)}get data(){return r(this,n)}set data(a){((n,t,e,a)=>{d(n,t,"write to private field"),a?a.call(n,e):t.set(n,e)})(this,n,a),l(this,t,e).call(this)}}n=new WeakMap,t=new WeakSet,e=function(){this.shadowRoot.innerHTML=`\n <style>\n :host {\n display: flex;\n gap: 16px;\n padding: 16px;\n overflow-x: auto;\n font-family: system-ui, -apple-system, sans-serif;\n }\n .column {\n background: #f1f2f4;\n border-radius: 8px;\n width: 280px;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n max-height: 100%;\n }\n .column-header {\n padding: 12px;\n font-weight: bold;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .items-container {\n flex: 1;\n padding: 8px;\n min-height: 50px;\n }\n .item {\n background: white;\n border-radius: 4px;\n padding: 12px;\n margin-bottom: 8px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n cursor: grab;\n }\n .item:active {\n cursor: grabbing;\n }\n .item.dragging {\n opacity: 0.5;\n }\n .items-container.drag-over {\n background: rgba(0,0,0,0.05);\n }\n </style>\n ${r(this,n).map(n=>`\n <div class="column" data-id="${n.id}">\n <div class="column-header">\n <span>${n.title}</span>\n </div>\n <div class="items-container" data-column-id="${n.id}">\n ${(n.items||[]).map(t=>`\n <div class="item" draggable="true" data-id="${t.id}" data-column-id="${n.id}">\n ${t.content}\n </div>\n `).join("")}\n </div>\n </div>\n `).join("")}\n `,l(this,t,a).call(this)},a=function(){const n=this.shadowRoot.querySelectorAll(".item"),e=this.shadowRoot.querySelectorAll(".items-container");n.forEach(n=>{n.addEventListener("dragstart",t=>{n.classList.add("dragging"),t.dataTransfer.setData("text/plain",JSON.stringify({itemId:n.dataset.id,fromColumnId:n.dataset.columnId}))}),n.addEventListener("dragend",()=>{n.classList.remove("dragging")})}),e.forEach(n=>{n.addEventListener("dragover",t=>{t.preventDefault(),n.classList.add("drag-over")}),n.addEventListener("dragleave",()=>{n.classList.remove("drag-over")}),n.addEventListener("drop",e=>{e.preventDefault(),n.classList.remove("drag-over");const a=JSON.parse(e.dataTransfer.getData("text/plain"));l(this,t,i).call(this,a.itemId,a.fromColumnId,n.dataset.columnId)})})},i=function(a,i,s){if(i===s)return;const d=r(this,n).find(n=>n.id===i),o=r(this,n).find(n=>n.id===s),c=d.items.findIndex(n=>n.id===a),[m]=d.items.splice(c,1);o.items.push(m),l(this,t,e).call(this),this.dispatchEvent(new CustomEvent("@update",{detail:r(this,n),bubbles:!0,composed:!0}))},customElements.define("web-kanban",c);export{c as Kanban};
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ApigoKanban={})}(this,function(e){"use strict";var t,n,a,i,d,s=e=>{throw TypeError(e)},o=(e,t,n)=>t.has(e)||s("Cannot "+n),r=(e,t,n)=>(o(e,t,"read from private field"),n?n.call(e):t.get(e)),l=(e,t,n)=>t.has(e)?s("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),c=(e,t,n)=>(o(e,t,"access private method"),n);class p extends HTMLElement{constructor(){super(),l(this,n),l(this,t,[]),this.attachShadow({mode:"open"})}connectedCallback(){c(this,n,a).call(this)}get data(){return r(this,t)}set data(e){((e,t,n,a)=>{o(e,t,"write to private field"),a?a.call(e,n):t.set(e,n)})(this,t,e),c(this,n,a).call(this)}}t=new WeakMap,n=new WeakSet,a=function(){this.shadowRoot.innerHTML=`\n <style>\n :host {\n display: flex;\n gap: 16px;\n padding: 16px;\n overflow-x: auto;\n font-family: system-ui, -apple-system, sans-serif;\n }\n .column {\n background: #f1f2f4;\n border-radius: 8px;\n width: 280px;\n min-width: 280px;\n display: flex;\n flex-direction: column;\n max-height: 100%;\n }\n .column-header {\n padding: 12px;\n font-weight: bold;\n display: flex;\n justify-content: space-between;\n align-items: center;\n }\n .items-container {\n flex: 1;\n padding: 8px;\n min-height: 50px;\n }\n .item {\n background: white;\n border-radius: 4px;\n padding: 12px;\n margin-bottom: 8px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n cursor: grab;\n }\n .item:active {\n cursor: grabbing;\n }\n .item.dragging {\n opacity: 0.5;\n }\n .items-container.drag-over {\n background: rgba(0,0,0,0.05);\n }\n </style>\n ${r(this,t).map(e=>`\n <div class="column" data-id="${e.id}">\n <div class="column-header">\n <span>${e.title}</span>\n </div>\n <div class="items-container" data-column-id="${e.id}">\n ${(e.items||[]).map(t=>`\n <div class="item" draggable="true" data-id="${t.id}" data-column-id="${e.id}">\n ${t.content}\n </div>\n `).join("")}\n </div>\n </div>\n `).join("")}\n `,c(this,n,i).call(this)},i=function(){const e=this.shadowRoot.querySelectorAll(".item"),t=this.shadowRoot.querySelectorAll(".items-container");e.forEach(e=>{e.addEventListener("dragstart",t=>{e.classList.add("dragging"),t.dataTransfer.setData("text/plain",JSON.stringify({itemId:e.dataset.id,fromColumnId:e.dataset.columnId}))}),e.addEventListener("dragend",()=>{e.classList.remove("dragging")})}),t.forEach(e=>{e.addEventListener("dragover",t=>{t.preventDefault(),e.classList.add("drag-over")}),e.addEventListener("dragleave",()=>{e.classList.remove("drag-over")}),e.addEventListener("drop",t=>{t.preventDefault(),e.classList.remove("drag-over");const a=JSON.parse(t.dataTransfer.getData("text/plain"));c(this,n,d).call(this,a.itemId,a.fromColumnId,e.dataset.columnId)})})},d=function(e,i,d){if(i===d)return;const s=r(this,t).find(e=>e.id===i),o=r(this,t).find(e=>e.id===d),l=s.items.findIndex(t=>t.id===e),[p]=s.items.splice(l,1);o.items.push(p),c(this,n,a).call(this),this.dispatchEvent(new CustomEvent("@update",{detail:r(this,t),bubbles:!0,composed:!0}))},customElements.define("web-kanban",p),"undefined"!=typeof globalThis&&globalThis.Component&&globalThis.Component.register("Kanban",e=>{const t=document.createElement("web-kanban");e.appendChild(t),e.kanbanInstance=t,e.state.__watch("data",e=>t.data=e),e.state.data&&(t.data=e.state.data),t.addEventListener("@update",t=>{e.state.data=t.detail,e.dispatchEvent(new CustomEvent("update",{detail:t.detail}))})}),"undefined"!=typeof globalThis&&(globalThis.Kanban=p),e.Kanban=p,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})});
|
||||||
|
|||||||
15
kanbanTODO.md
Normal file
15
kanbanTODO.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# kanban TODO
|
||||||
|
|
||||||
|
- [x] 架构对齐:Align with `base` project's "No ESM" design.
|
||||||
|
- [ ] 构建配置:Modify `vite.config.js` to output only UMD (`kanban.js` and `kanban.min.js`).
|
||||||
|
- [ ] 源码重构:
|
||||||
|
- [ ] 注册 `Kanban` 为全局组件 (`globalThis.Component.register`) 以对齐状态框架。
|
||||||
|
- [ ] 确保 `Kanban` 类在 `globalThis` 上可用。
|
||||||
|
- [ ] 测试验证:运行 `npm test` 确保功能无损。
|
||||||
|
- [ ] 文档更新:
|
||||||
|
- [ ] 更新 `package.json` 版本号。
|
||||||
|
- [ ] 更新 `README.md` 以反映组件化用法。
|
||||||
|
- [ ] 更新 `CHANGELOG.md`。
|
||||||
|
|
||||||
|
## 当前状态 (v1.0.1)
|
||||||
|
- 首次渲染耗时: 9.40ms (from TEST.md)
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@web/kanban",
|
"name": "@apigo.cc/kanban",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@web/kanban",
|
"name": "@apigo.cc/kanban",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.40.0",
|
"@playwright/test": "^1.40.0",
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "@apigo.cc/kanban",
|
"name": "@apigo.cc/kanban",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "dist/kanban.js",
|
"main": "dist/kanban.js",
|
||||||
"module": "dist/kanban.js",
|
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
],
|
],
|
||||||
|
|||||||
@ -87,4 +87,4 @@ Error generating stack: `+l.message+`
|
|||||||
<div id='root'></div>
|
<div id='root'></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<template id="playwrightReportBase64">data:application/zip;base64,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</template>
|
<template id="playwrightReportBase64">data:application/zip;base64,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</template>
|
||||||
48
scripts/publish.js
Normal file
48
scripts/publish.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { execSync } from 'child_process';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 获取最新 tag
|
||||||
|
let tag;
|
||||||
|
try {
|
||||||
|
tag = execSync('git describe --tags --abbrev=0', { encoding: 'utf8' }).trim();
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error('Failed to find git tags. Please make sure the repository has tags (e.g., v1.0.0) before publishing.');
|
||||||
|
}
|
||||||
|
// 去掉 v 前缀
|
||||||
|
const version = tag.startsWith('v') ? tag.slice(1) : tag;
|
||||||
|
|
||||||
|
console.log(`Latest git tag: ${tag}, Version to publish: ${version}`);
|
||||||
|
|
||||||
|
// 2. 读取并更新 package.json
|
||||||
|
const pkgPath = path.join(__dirname, '../package.json');
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||||
|
|
||||||
|
// 保持原有名称(如果已经带有 @apigo.cc/ 前缀)或替换前缀
|
||||||
|
if (!pkg.name.startsWith('@apigo.cc/')) {
|
||||||
|
const baseName = pkg.name.includes('/') ? pkg.name.split('/')[1] : pkg.name;
|
||||||
|
pkg.name = `@apigo.cc/${baseName}`;
|
||||||
|
}
|
||||||
|
pkg.version = version;
|
||||||
|
|
||||||
|
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
||||||
|
console.log(`Updated package.json: name=${pkg.name}, version=${pkg.version}`);
|
||||||
|
|
||||||
|
// 3. 构建
|
||||||
|
console.log('Running build...');
|
||||||
|
execSync('npm run build', { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||||
|
|
||||||
|
// 4. 发布
|
||||||
|
console.log('Publishing to npm...');
|
||||||
|
const args = process.argv.slice(2).join(' ');
|
||||||
|
execSync(`npm publish --access public ${args}`, { stdio: 'inherit', cwd: path.join(__dirname, '..') });
|
||||||
|
|
||||||
|
console.log('Publish successful!');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Publish failed:', error.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
24
src/index.js
24
src/index.js
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @web/kanban
|
* @apigo.cc/kanban
|
||||||
* 原生 ESM 看板引擎
|
* 原生 ESM 看板引擎
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -152,3 +152,25 @@ export class Kanban extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('web-kanban', Kanban);
|
customElements.define('web-kanban', Kanban);
|
||||||
|
|
||||||
|
// 注册为全局组件以对齐状态框架
|
||||||
|
if (typeof globalThis !== 'undefined' && globalThis.Component) {
|
||||||
|
globalThis.Component.register('Kanban', container => {
|
||||||
|
const kanban = document.createElement('web-kanban');
|
||||||
|
container.appendChild(kanban);
|
||||||
|
container.kanbanInstance = kanban;
|
||||||
|
|
||||||
|
container.state.__watch('data', val => kanban.data = val);
|
||||||
|
if (container.state.data) kanban.data = container.state.data;
|
||||||
|
|
||||||
|
kanban.addEventListener('@update', e => {
|
||||||
|
container.state.data = e.detail;
|
||||||
|
container.dispatchEvent(new CustomEvent('update', { detail: e.detail }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 挂载到全局
|
||||||
|
if (typeof globalThis !== 'undefined') {
|
||||||
|
globalThis.Kanban = Kanban;
|
||||||
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
<script type="importmap">
|
<script type="importmap">
|
||||||
{
|
{
|
||||||
"imports": {
|
"imports": {
|
||||||
"@web/kanban": "../src/index.js"
|
"@apigo.cc/kanban": "../src/index.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<web-kanban id="kanban"></web-kanban>
|
<web-kanban id="kanban"></web-kanban>
|
||||||
</div>
|
</div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import '@web/kanban';
|
import '@apigo.cc/kanban';
|
||||||
|
|
||||||
const kanban = document.getElementById('kanban');
|
const kanban = document.getElementById('kanban');
|
||||||
kanban.data = [
|
kanban.data = [
|
||||||
|
|||||||
@ -5,30 +5,30 @@ import { resolve } from 'path';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@web/kanban': resolve(__dirname, 'src/index.js'),
|
'@apigo.cc/kanban': resolve(__dirname, 'src/index.js'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
lib: {
|
lib: {
|
||||||
entry: 'src/index.js',
|
entry: 'src/index.js',
|
||||||
name: 'Kanban',
|
name: 'ApigoKanban',
|
||||||
fileName: (format) => `kanban${format === 'es' ? '' : '.min'}.js`,
|
formats: ['umd'],
|
||||||
formats: ['es'],
|
|
||||||
},
|
},
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: [
|
output: [
|
||||||
{
|
{
|
||||||
format: 'es',
|
format: 'umd',
|
||||||
|
name: 'ApigoKanban',
|
||||||
entryFileNames: 'kanban.js',
|
entryFileNames: 'kanban.js',
|
||||||
plugins: [], // 不压缩
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
format: 'es',
|
format: 'umd',
|
||||||
|
name: 'ApigoKanban',
|
||||||
entryFileNames: 'kanban.min.js',
|
entryFileNames: 'kanban.min.js',
|
||||||
plugins: [terser()], // 压缩
|
plugins: [terser()],
|
||||||
},
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
minify: false, // 由 rollupOptions 控制
|
minify: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user