Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ jspm_packages/

# dotenv environment variable files
.env
.env.*
.env.development.local
.env.test.local
.env.production.local
Expand Down
28 changes: 28 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Node.js dependencies
node_modules/

# Build outputs
build/
dist/

# Logs
*.log

# Environment files
.env*

# Tests and coverage
coverage/
__tests__/

# Tooling and configs
.eslintrc*
eslint.config.*
.prettierrc*
.prettierignore
.vscode/
.idea/

# Misc
*.tgz
*.tsbuildinfo
4 changes: 4 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
dist
build
coverage
node_modules
.yarn
package-lock.json
yarn.lock
pnpm-lock.yaml
87 changes: 52 additions & 35 deletions .specify/memory/constitution.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,67 @@
# [PROJECT_NAME] Constitution
<!-- Example: Spec Constitution, TaskFlow Constitution, etc. -->
<!--
Sync Impact Report:
- Version change: 1.0.1 → 1.0.2
- Modified principles: None
- Added sections: None
- Removed sections: None
- Templates requiring updates:
- .specify/templates/plan-template.md ✅
- .specify/templates/spec-template.md ✅
- .specify/templates/tasks-template.md ✅
- .specify/templates/agent-file-template.md ✅
- .specify/templates/checklist-template.md ✅
- Follow-up TODOs: None
-->
# Magic Drag Constitution

## Core Principles

### [PRINCIPLE_1_NAME]
<!-- Example: I. Library-First -->
[PRINCIPLE_1_DESCRIPTION]
<!-- Example: Every feature starts as a standalone library; Libraries must be self-contained, independently testable, documented; Clear purpose required - no organizational-only libraries -->
### I. Library-First, Clear Boundaries
Each module MUST have a single, explicit responsibility and avoid hidden side
-effects. The manager layer MUST focus on coordination and dispatch, while
serialization/deserialization and DOM ownership stay with MagicDrag subclasses.
This keeps the library composable and testable.

### [PRINCIPLE_2_NAME]
<!-- Example: II. CLI Interface -->
[PRINCIPLE_2_DESCRIPTION]
<!-- Example: Every library exposes functionality via CLI; Text in/out protocol: stdin/args → stdout, errors → stderr; Support JSON + human-readable formats -->
### II. Type Safety First
TypeScript types MUST be explicit for public APIs and event payloads. Avoid
unsafe casts and prefer precise generics. Any change that weakens type safety
requires documented justification and reviewer approval.

### [PRINCIPLE_3_NAME]
<!-- Example: III. Test-First (NON-NEGOTIABLE) -->
[PRINCIPLE_3_DESCRIPTION]
<!-- Example: TDD mandatory: Tests written → User approved → Tests fail → Then implement; Red-Green-Refactor cycle strictly enforced -->
### III. Event-Driven Extensibility
New behavior MUST be added through event registration and dispatch rather than
hard-coded branching. Event systems MUST allow filtering by channel, type, and
instance ID to prevent cross-talk.

### [PRINCIPLE_4_NAME]
<!-- Example: IV. Integration Testing -->
[PRINCIPLE_4_DESCRIPTION]
<!-- Example: Focus areas requiring integration tests: New library contract tests, Contract changes, Inter-service communication, Shared schemas -->
### IV. Testing Discipline (Contextual)
Tests MUST be added when the feature specification requests them. For behavioral
changes that affect core flows, existing tests MUST be updated or extended to
cover the new behavior. Do not remove tests to make failures disappear.

### [PRINCIPLE_5_NAME]
<!-- Example: V. Observability, VI. Versioning & Breaking Changes, VII. Simplicity -->
[PRINCIPLE_5_DESCRIPTION]
<!-- Example: Text I/O ensures debuggability; Structured logging required; Or: MAJOR.MINOR.BUILD format; Or: Start simple, YAGNI principles -->
### V. Observability & Diagnostics
Unhandled or unexpected signals MUST be observable (structured logs or counters).
Errors SHOULD surface actionable context such as message type, channel, and
instance ID.

## [SECTION_2_NAME]
<!-- Example: Additional Constraints, Security Requirements, Performance Standards, etc. -->
## Engineering Constraints

[SECTION_2_CONTENT]
<!-- Example: Technology stack requirements, compliance standards, deployment policies, etc. -->
- TypeScript is the source of truth; do not introduce `any` in new code.
- Do not edit files under `node_modules/`.
- Avoid writing to `.history/` or relying on its contents.
- Prefer existing project dependencies over adding new ones.

## [SECTION_3_NAME]
<!-- Example: Development Workflow, Review Process, Quality Gates, etc. -->
## Workflow & Quality Gates

[SECTION_3_CONTENT]
<!-- Example: Code review requirements, testing gates, deployment approval process, etc. -->
- Lint and type-check MUST pass before release-quality changes are accepted.
- Update the CHANGELOG under `[UnReleased]` before pushing changes that modify
behavior or public APIs.
- All changes MUST reference a feature spec or task plan when applicable.

## Governance
<!-- Example: Constitution supersedes all other practices; Amendments require documentation, approval, migration plan -->

[GOVERNANCE_RULES]
<!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
The constitution supersedes local conventions. Amendments require a written
rationale, version bump, and review. Versioning follows semantic versioning:
MAJOR for breaking governance changes, MINOR for new or expanded principles,
PATCH for clarifications. Compliance checks must be performed during plan
reviews and before merging.

**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
<!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
**Version**: 1.0.2 | **Ratified**: 2025-01-20 | **Last Amended**: 2025-01-20
6 changes: 6 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,9 @@ yarn format # 代码格式化
2. 需要在每个 Tab 中调用 `MagicDragManager.registerClass()` 注册可拖拽类
3. BroadcastChannel 只在同源(Same Origin)的 Tab 之间工作
4. 跨 Tab 传输的数据必须是可序列化的(无法传输函数、DOM 元素等)

## Active Technologies
- TypeScript ~5.6.3 + @system-ui-js/multi-drag, @system-ui-js/development-base, BroadcastChannel API (001-manager-dispatch)

## Recent Changes
- 001-manager-dispatch: Added TypeScript ~5.6.3 + @system-ui-js/multi-drag, @system-ui-js/development-base, BroadcastChannel API
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ The format is based on Keep a Changelog and this project adheres to Semantic Ver

## Unreleased

### Added
- 支持按通道名注册事件监听器,并提供全局事件分发接口
- MagicDrag 子类可通过静态 channelName 指定跨标签页通信通道

### Changed
- Manager 统一分发拖拽信号并在无监听器时记录可观测日志
- 跨标签页拖拽 activeTabId 在拖拽开始与进入目标标签页时更新

### Fixed
- 移除无用的测试文件 `src/__tests__/sum.test.ts`
- 修复 tsconfig.build.json 配置冲突:将 `noEmit: false` 改为 `emitDeclarationOnly: true`,解决 `allowImportingTsExtensions` 只能在 `noEmit` 或 `emitDeclarationOnly` 时使用的 TypeScript 编译错误
- 修复 ESLint 错误:将 `MagicDrag.channelName` 改为 `readonly`,符合 sonarjs/public-static-readonly 规则
- 修复 ESLint 错误:移除冗余的类型别名 `MagicDragAnyEventListenerStore`,符合 sonarjs/redundant-type-aliases 规则
- 修复拖出所有 Tab 时无法触发 DRAG_ABORT 的问题:在 handleExternalDragMove 中,当鼠标离开当前 Tab 时,如果 `activeTabId` 等于当前 Tab ID,则将其设为 null,确保 MagicDrag.handleDragEnd 能正确判断 abort 条件

## 0.1.0 - 2025-11-16

Expand Down
2 changes: 2 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ const baseIgnores = [

const projectIgnores = [
'dist',
'build',
'coverage',
'node_modules',
'*.min.js',
'playwright-report',
'test-results'
]
Expand Down
34 changes: 34 additions & 0 deletions specs/001-manager-dispatch/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Specification Quality Checklist: Manager Dispatch Refactor

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-01-19
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

- 无
77 changes: 77 additions & 0 deletions specs/001-manager-dispatch/contracts/drag-signals.openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
openapi: 3.0.3
info:
title: Magic Drag Signal Contracts
version: 1.0.0
description: Event-style signal contracts for MagicDragManager dispatch and listener routing.
paths: {}
components:
schemas:
MagicDragMessageType:
type: string
enum:
- magic_drag_start
- magic_drag_move
- magic_drag_end
- magic_drag_enter_tab
- magic_drag_leave_tab
- magic_drag_drop
- magic_drag_abort
- magic_drag_tab_activated
- magic_drag_heartbeat
- magic_drag_heartbeat_ack
ScreenPosition:
type: object
required: [screenX, screenY]
properties:
screenX:
type: number
screenY:
type: number
DragOffset:
type: object
required: [x, y]
properties:
x:
type: number
y:
type: number
SerializedData:
type: object
required: [instanceId, className, pose, customData]
properties:
instanceId:
type: string
className:
type: string
pose:
type: object
additionalProperties: true
customData:
type: object
additionalProperties: true
dragOffset:
$ref: '#/components/schemas/DragOffset'
MagicDragMessagePayload:
type: object
required: [timestamp]
properties:
serializedData:
$ref: '#/components/schemas/SerializedData'
screenPosition:
$ref: '#/components/schemas/ScreenPosition'
timestamp:
type: number
MagicDragMessage:
type: object
required: [type, instanceId, sourceTabId, payload]
properties:
type:
$ref: '#/components/schemas/MagicDragMessageType'
instanceId:
type: string
sourceTabId:
type: string
targetTabId:
type: string
payload:
$ref: '#/components/schemas/MagicDragMessagePayload'
34 changes: 34 additions & 0 deletions specs/001-manager-dispatch/data-model.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Data Model

## Entities

### DragType
- name: string
- channelName: string
- className: string
- constructor: MagicDragConstructor

### SignalChannel
- name: string
- dragTypes: DragType[]

### ActiveTabState
- activeTabId: string | null
- sourceTabId: string | null
- draggingInstanceId: string | null

## Relationships
- DragType uses SignalChannel by channelName.
- SignalChannel can be shared by multiple DragType entries.
- ActiveTabState is maintained by MagicDragManager and updated on drag start and
enter-tab transitions.

## Validation Rules
- channelName MUST be a non-empty string.
- dragTypes may share the same channelName (no uniqueness requirement).
- activeTabId MUST be set on drag start and updated on enter-tab events.

## State Transitions
- idle → dragging: on DRAG_START (activeTabId = sourceTabId)
- dragging → entered-target: on DRAG_ENTER_TAB (activeTabId = targetTabId)
- dragging/entered-target → idle: on DRAG_END/DRAG_ABORT/DRAG_DROP
Loading