@f-ewald/components 1.1.1 → 1.2.0

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanban-board.js","sourceRoot":"","sources":["../src/kanban-board.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { repeat } from \"lit/directives/repeat.js\";\nimport { iconCalendar, iconClock, iconTag } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\nimport \"./kanban-column.js\";\nimport \"./kanban-card.js\";\nimport \"./popover-panel.js\";\nimport \"./radio-pills.js\";\nimport \"./relative-time.js\";\n\n/** One card in a column. `id` is stable identity; everything else is display data. */\nexport interface KanbanCardData {\n /** Stable unique identifier used as the drag/move key. */\n id: string;\n /** Ticket identifier shown in the overview and detail, e.g. `\"PROJ-142\"`. */\n ticket: string;\n /** Card title shown in the overview and detail. */\n title: string;\n /** Longer description shown only in the detail popover. */\n description?: string;\n /** ISO 8601 / SQLite `datetime` string shown in the detail popover. */\n createdAt?: string;\n /** ISO 8601 / SQLite `datetime` string shown in the detail popover. */\n updatedAt?: string;\n}\n\n/** One column: its `id`, header `title`, and ordered `cards`. The column is the card's state. */\nexport interface KanbanColumnData {\n /** Stable unique identifier, also the card's state value. */\n id: string;\n /** Column title shown in the header and the detail state selector. */\n title: string;\n /** Cards in display order. */\n cards: KanbanCardData[];\n}\n\n/** `card-move` detail: which card moved, and where from/to (`toIndex` is its final index in `toColumnId`). */\nexport interface KanbanCardMoveDetail {\n cardId: string;\n fromColumnId: string;\n toColumnId: string;\n toIndex: number;\n}\n\n/** `card-open` detail: the card whose detail view was opened. */\nexport interface KanbanCardOpenDetail {\n cardId: string;\n}\n\ninterface GrabState {\n cardId: string;\n fromColumnId: string;\n originIndex: number;\n columnId: string;\n index: number;\n}\n\ninterface DragState {\n cardId: string;\n fromColumnId: string;\n originIndex: number;\n}\n\ninterface Indicator {\n columnId: string;\n index: number;\n}\n\n/** Duration (ms) of the warm \"just moved\" highlight flashed on a card after it lands. */\nconst HIGHLIGHT_MS = 1400;\n\n/**\n * A configurable kanban board: a horizontally scrolling row of columns, each\n * holding cards. **A card's column is its state** — moving a card to another\n * column (by drag-and-drop, keyboard, or the detail popover's state selector)\n * changes its state, and the board emits a single `card-move` for all three.\n *\n * Data-driven: set the `columns` property to `KanbanColumnData[]`. The board\n * keeps its own working copy and mutates it optimistically on every move, so it\n * works standalone; re-assign `columns` at any time to stay controlled from a\n * store. Cards show only their ticket number and title in the overview; the\n * full detail (description, state, created/updated timestamps) opens in a\n * screen-centered `popover-panel`.\n *\n * Pointer drag-and-drop supports both cross-column moves and within-column\n * reordering with a live drop indicator (set `reorderable` false to keep only\n * cross-column moves when intra-column order isn't persisted). Keyboard parity:\n * focus a card and press Space to pick it up, arrow keys to move it (left/right\n * across columns, up/down within a column), Space to drop, or Escape to cancel;\n * Enter opens the detail. Moves are announced in a polite live region, and the\n * moved card briefly flashes a warm highlight so you can see where it landed.\n *\n * Set `manual` for a server-authoritative board (API + WebSocket/SSE): every\n * move still emits `card-move`, but the board does NOT apply it locally, so it\n * reflects only what you assign to `columns` — e.g. the change echoed back over\n * the socket. The default is optimistic local updates.\n *\n * @element kanban-board\n * @fires card-open - A card's detail view was opened; detail: { cardId }.\n * @fires card-move - A card changed column/position; detail: { cardId, fromColumnId, toColumnId, toIndex }.\n */\n@customElement(\"kanban-board\")\nexport class KanbanBoard extends LitElement {\n /** Columns (with their cards) to render, in display order. */\n @property({ attribute: false }) columns: KanbanColumnData[] = [];\n /** Accessible label for the board's group role. */\n @property() label = \"Board\";\n /**\n * Server-authoritative mode. When true, moves emit `card-move` but are not\n * applied to the board locally; it reflects only what you assign to\n * `columns` (e.g. echoed back over WebSocket/SSE), keeping the server as the\n * single source of truth. Defaults to optimistic local updates.\n */\n @property({ type: Boolean, reflect: true }) manual = false;\n /**\n * Whether cards can be reordered within a column. Defaults to true. Set false\n * when intra-column order isn't persisted (no server `rank`): drag and\n * keyboard still move cards *between* columns (appended to the target), but\n * reordering inside a column is disabled, so the UI only offers what sticks.\n */\n @property({ type: Boolean, reflect: true }) reorderable = true;\n\n @state() private _cols: KanbanColumnData[] = [];\n @state() private _openCardId: string | null = null;\n @state() private _drag: DragState | null = null;\n @state() private _pointer: Indicator | null = null;\n @state() private _grab: GrabState | null = null;\n @state() private _liveMessage = \"\";\n @state() private _highlighted = new Set<string>();\n\n #refocus: string | null = null;\n #pendingHighlight: string | null = null;\n #highlightTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n .board {\n display: flex;\n align-items: flex-start;\n gap: 1rem;\n overflow-x: auto;\n padding-bottom: 0.25rem;\n }\n .drop-indicator {\n height: 0.125rem;\n background: var(--ui-primary, #4f46e5);\n border-radius: 999px;\n }\n .detail {\n display: flex;\n flex-direction: column;\n gap: 0.75rem;\n padding: 0.75rem;\n }\n .detail-desc {\n margin: 0;\n font-size: var(--ui-font-size, 0.875rem);\n line-height: var(--ui-line-height-normal, 1.5);\n color: var(--ui-text, #0f172a);\n }\n .detail-muted {\n color: var(--ui-text-muted, #64748b);\n }\n .detail-field {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n }\n .detail-label {\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n color: var(--ui-text-muted, #64748b);\n }\n .detail-meta {\n margin: 0;\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n }\n .detail-meta-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n }\n .detail-meta-row dt {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n color: var(--ui-text-muted, #64748b);\n font-weight: var(--ui-font-weight-medium, 500);\n }\n .detail-meta-row dt svg {\n display: inline-flex;\n }\n .detail-meta-row dd {\n margin: 0;\n color: var(--ui-text, #0f172a);\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n `,\n ];\n\n protected override willUpdate(changed: PropertyValues): void {\n if (changed.has(\"columns\")) {\n this._cols = this.columns.map((column) => ({\n id: column.id,\n title: column.title,\n cards: column.cards.map((card) => ({ ...card })),\n }));\n // In manual mode the highlight is deferred until the moved card actually\n // arrives via a `columns` reassignment (e.g. the socket echo).\n if (this.#pendingHighlight && this.#findCard(this.#pendingHighlight)) {\n this.#highlight(this.#pendingHighlight);\n }\n this.#pendingHighlight = null;\n }\n }\n\n protected override updated(): void {\n if (this.#refocus) {\n const card = this.renderRoot.querySelector<HTMLElement>(\n `kanban-card[data-card-id=\"${this.#refocus}\"]`,\n );\n card?.focus();\n this.#refocus = null;\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._grab = null;\n this._drag = null;\n this._pointer = null;\n for (const timer of this.#highlightTimers.values()) clearTimeout(timer);\n this.#highlightTimers.clear();\n }\n\n /** Returns the card, its column, and index for a card id, or null if unknown. */\n #findCard(cardId: string): { card: KanbanCardData; column: KanbanColumnData; index: number } | null {\n for (const column of this._cols) {\n const index = column.cards.findIndex((card) => card.id === cardId);\n if (index >= 0) return { card: column.cards[index], column, index };\n }\n return null;\n }\n\n /** Number of cards currently in a column (0 if unknown). */\n #columnCount(columnId: string): number {\n return this._cols.find((column) => column.id === columnId)?.cards.length ?? 0;\n }\n\n /** Flashes the warm \"just moved\" highlight on a card, clearing it after HIGHLIGHT_MS. */\n #highlight(cardId: string): void {\n const existing = this.#highlightTimers.get(cardId);\n if (existing) clearTimeout(existing);\n const next = new Set(this._highlighted);\n next.add(cardId);\n this._highlighted = next;\n this.#highlightTimers.set(\n cardId,\n setTimeout(() => {\n const remaining = new Set(this._highlighted);\n remaining.delete(cardId);\n this._highlighted = remaining;\n this.#highlightTimers.delete(cardId);\n }, HIGHLIGHT_MS),\n );\n }\n\n /** Applies a move to the working copy and emits `card-move`. `toIndex` is the destination index after removal. */\n #move(cardId: string, fromColumnId: string, toColumnId: string, toIndex: number): void {\n const cols = this._cols.map((column) => ({ ...column, cards: [...column.cards] }));\n const from = cols.find((column) => column.id === fromColumnId);\n const to = cols.find((column) => column.id === toColumnId);\n if (!from || !to) return;\n const index = from.cards.findIndex((card) => card.id === cardId);\n if (index < 0) return;\n const [card] = from.cards.splice(index, 1);\n const target = Math.max(0, Math.min(toIndex, to.cards.length));\n to.cards.splice(target, 0, card);\n if (!this.manual) this._cols = cols;\n this.dispatchEvent(\n new CustomEvent<KanbanCardMoveDetail>(\"card-move\", {\n detail: { cardId, fromColumnId, toColumnId, toIndex: target },\n bubbles: true,\n composed: true,\n }),\n );\n // Optimistic: highlight now (the card is already at its new position).\n // Manual: defer until the move is echoed back via `columns`.\n if (this.manual) this.#pendingHighlight = cardId;\n else this.#highlight(cardId);\n }\n\n /** Converts a DOM insertion index (which counts the moving card) into a destination index after removal. */\n #toDestIndex(fromColumnId: string, originIndex: number, toColumnId: string, domIndex: number): number {\n return fromColumnId === toColumnId && domIndex > originIndex ? domIndex - 1 : domIndex;\n }\n\n /** Computes the DOM insertion index within a column from the pointer's vertical position. */\n #pointerIndex(columnId: string, clientY: number): number {\n const cards = [\n ...this.renderRoot.querySelectorAll<HTMLElement>(`kanban-card[data-column-id=\"${columnId}\"]`),\n ];\n for (let i = 0; i < cards.length; i++) {\n const rect = cards[i].getBoundingClientRect();\n if (clientY < rect.top + rect.height / 2) return i;\n }\n return cards.length;\n }\n\n #onDragStart(event: DragEvent, columnId: string, cardId: string): void {\n const column = this._cols.find((entry) => entry.id === columnId);\n const originIndex = column ? column.cards.findIndex((card) => card.id === cardId) : 0;\n this._grab = null;\n this._drag = { cardId, fromColumnId: columnId, originIndex };\n this._pointer = { columnId, index: originIndex };\n if (event.dataTransfer) {\n event.dataTransfer.effectAllowed = \"move\";\n try {\n event.dataTransfer.setData(\"text/plain\", cardId);\n } catch {\n /* some browsers disallow setData outside trusted events */\n }\n }\n }\n\n #onDragOver(event: DragEvent, columnId: string): void {\n if (!this._drag) return;\n event.preventDefault();\n if (event.dataTransfer) event.dataTransfer.dropEffect = \"move\";\n const index = this.#pointerIndex(columnId, event.clientY);\n if (this._pointer?.columnId !== columnId || this._pointer.index !== index) {\n this._pointer = { columnId, index };\n }\n }\n\n #onDrop(event: DragEvent, columnId: string): void {\n if (!this._drag) return;\n event.preventDefault();\n const { cardId, fromColumnId, originIndex } = this._drag;\n this._drag = null;\n this._pointer = null;\n if (!this.reorderable) {\n // Intra-column reordering is off: ignore same-column drops, and append\n // cross-column moves to the end of the destination.\n if (columnId === fromColumnId) return;\n this.#move(cardId, fromColumnId, columnId, this.#columnCount(columnId));\n return;\n }\n const domIndex = this.#pointerIndex(columnId, event.clientY);\n const dest = this.#toDestIndex(fromColumnId, originIndex, columnId, domIndex);\n this.#move(cardId, fromColumnId, columnId, dest);\n }\n\n #onDragEnd(): void {\n this._drag = null;\n this._pointer = null;\n }\n\n #onCardKeydown(event: KeyboardEvent, columnId: string, cardId: string): void {\n const grabbing = this._grab?.cardId === cardId;\n if (event.key === \"Enter\") {\n if (grabbing) return;\n event.preventDefault();\n this.#openDetail(cardId);\n return;\n }\n if (event.key === \" \" || event.key === \"Spacebar\") {\n event.preventDefault();\n if (grabbing) this.#commitGrab();\n else this.#startGrab(columnId, cardId);\n return;\n }\n if (!grabbing) return;\n switch (event.key) {\n case \"Escape\":\n event.preventDefault();\n this.#cancelGrab();\n break;\n case \"ArrowUp\":\n event.preventDefault();\n this.#grabMove(0, -1);\n break;\n case \"ArrowDown\":\n event.preventDefault();\n this.#grabMove(0, 1);\n break;\n case \"ArrowLeft\":\n event.preventDefault();\n this.#grabMove(-1, 0);\n break;\n case \"ArrowRight\":\n event.preventDefault();\n this.#grabMove(1, 0);\n break;\n default:\n break;\n }\n }\n\n #startGrab(columnId: string, cardId: string): void {\n const column = this._cols.find((entry) => entry.id === columnId);\n const index = column ? column.cards.findIndex((card) => card.id === cardId) : 0;\n this._grab = { cardId, fromColumnId: columnId, originIndex: index, columnId, index };\n this.#refocus = cardId;\n const ticket = column?.cards[index]?.ticket ?? \"card\";\n this.#announce(\n `Picked up ${ticket}. Use the arrow keys to move it, space to drop, or escape to cancel.`,\n );\n }\n\n #grabMove(columnDelta: number, indexDelta: number): void {\n const grab = this._grab;\n if (!grab) return;\n let columnIndex = this._cols.findIndex((column) => column.id === grab.columnId);\n if (columnIndex < 0) return;\n let index = grab.index;\n if (columnDelta !== 0) {\n const next = columnIndex + columnDelta;\n if (next < 0 || next >= this._cols.length) return;\n columnIndex = next;\n // With reordering off, a cross-column move lands at the end.\n index = this.reorderable\n ? Math.min(index, this._cols[columnIndex].cards.length)\n : this._cols[columnIndex].cards.length;\n } else {\n if (!this.reorderable) return; // no intra-column reordering\n const max = this._cols[columnIndex].cards.length;\n index = Math.max(0, Math.min(max, index + indexDelta));\n }\n const column = this._cols[columnIndex];\n this._grab = { ...grab, columnId: column.id, index };\n this.#refocus = grab.cardId;\n const ticket = this.#findCard(grab.cardId)?.card.ticket ?? \"Card\";\n this.#announce(`${ticket} moved to ${column.title}, position ${index + 1}.`);\n }\n\n #commitGrab(): void {\n const grab = this._grab;\n if (!grab) return;\n if (!this.reorderable && grab.columnId === grab.fromColumnId) {\n // Nothing to persist for a same-column drop when reordering is off.\n this._grab = null;\n this.#refocus = grab.cardId;\n this.#announce(\"Returned to its position.\");\n return;\n }\n const dest = this.#toDestIndex(grab.fromColumnId, grab.originIndex, grab.columnId, grab.index);\n const column = this._cols.find((entry) => entry.id === grab.columnId);\n const ticket = this.#findCard(grab.cardId)?.card.ticket ?? \"Card\";\n this._grab = null;\n this.#move(grab.cardId, grab.fromColumnId, grab.columnId, dest);\n this.#refocus = grab.cardId;\n this.#announce(`${ticket} dropped in ${column?.title ?? \"\"}.`);\n }\n\n #cancelGrab(): void {\n const grab = this._grab;\n this._grab = null;\n this.#refocus = grab?.cardId ?? null;\n this.#announce(\"Move cancelled.\");\n }\n\n #announce(message: string): void {\n this._liveMessage = message;\n }\n\n #openDetail(cardId: string): void {\n if (this._grab) return;\n this._openCardId = cardId;\n this.dispatchEvent(\n new CustomEvent<KanbanCardOpenDetail>(\"card-open\", {\n detail: { cardId },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n #closeDetail(): void {\n this._openCardId = null;\n }\n\n #onStateChange(cardId: string, fromColumnId: string, toColumnId: string): void {\n if (!toColumnId || toColumnId === fromColumnId) return;\n const dest = this._cols.find((column) => column.id === toColumnId);\n this.#move(cardId, fromColumnId, toColumnId, dest ? dest.cards.length : 0);\n }\n\n #renderColumn(column: KanbanColumnData, indicator: Indicator | null, dragCardId: string | null) {\n let indicatorIndex = -1;\n if (indicator?.columnId === column.id) {\n if (this.reorderable) {\n indicatorIndex = indicator.index;\n } else {\n // Reordering off: only show an append indicator on a *different* column.\n const sourceColumnId = this._grab?.fromColumnId ?? this._drag?.fromColumnId ?? null;\n if (sourceColumnId !== null && sourceColumnId !== column.id) {\n indicatorIndex = column.cards.length;\n }\n }\n }\n return html`\n <kanban-column\n .heading=${column.title}\n .count=${column.cards.length}\n .empty=${column.cards.length === 0}\n .dragover=${this._pointer?.columnId === column.id}\n data-column-id=${column.id}\n @dragenter=${(event: DragEvent) => this.#onDragOver(event, column.id)}\n @dragover=${(event: DragEvent) => this.#onDragOver(event, column.id)}\n @drop=${(event: DragEvent) => this.#onDrop(event, column.id)}\n >\n ${repeat(\n column.cards,\n (card) => card.id,\n (card, i) => html`\n ${indicatorIndex === i\n ? html`<div class=\"drop-indicator\" aria-hidden=\"true\"></div>`\n : nothing}\n <kanban-card\n .ticket=${card.ticket}\n .heading=${card.title}\n data-card-id=${card.id}\n data-column-id=${column.id}\n draggable=\"true\"\n ?dragging=${dragCardId === card.id && this._drag !== null}\n ?grabbed=${this._grab?.cardId === card.id}\n ?just-moved=${this._highlighted.has(card.id)}\n @dragstart=${(event: DragEvent) => this.#onDragStart(event, column.id, card.id)}\n @click=${() => this.#openDetail(card.id)}\n @keydown=${(event: KeyboardEvent) => this.#onCardKeydown(event, column.id, card.id)}\n ></kanban-card>\n `,\n )}\n ${indicatorIndex === column.cards.length\n ? html`<div class=\"drop-indicator\" aria-hidden=\"true\"></div>`\n : nothing}\n </kanban-column>\n `;\n }\n\n #renderDetail() {\n const open = this._openCardId ? this.#findCard(this._openCardId) : null;\n return html`\n <popover-panel\n centered\n ?open=${open !== null}\n heading=${open?.card.title ?? \"\"}\n @panel-close=${() => this.#closeDetail()}\n >\n ${open\n ? html`\n <div class=\"detail\">\n ${open.card.description\n ? html`<p class=\"detail-desc\">${open.card.description}</p>`\n : html`<p class=\"detail-desc detail-muted\">No description.</p>`}\n <div class=\"detail-field\">\n <span class=\"detail-label\" id=\"kb-state-label\">State</span>\n <radio-pills\n aria-labelledby=\"kb-state-label\"\n .options=${this._cols.map((column) => ({\n value: column.id,\n label: column.title,\n }))}\n .value=${open.column.id}\n @change=${(event: CustomEvent<{ value: string }>) =>\n this.#onStateChange(open.card.id, open.column.id, event.detail.value)}\n ></radio-pills>\n </div>\n <dl class=\"detail-meta\">\n <div class=\"detail-meta-row\">\n <dt><span aria-hidden=\"true\">${iconTag(14)}</span> Ticket</dt>\n <dd>${open.card.ticket}</dd>\n </div>\n ${open.card.createdAt\n ? html`\n <div class=\"detail-meta-row\">\n <dt><span aria-hidden=\"true\">${iconCalendar(14)}</span> Created</dt>\n <dd><relative-time datetime=${open.card.createdAt}></relative-time></dd>\n </div>\n `\n : nothing}\n ${open.card.updatedAt\n ? html`\n <div class=\"detail-meta-row\">\n <dt><span aria-hidden=\"true\">${iconClock(14)}</span> Updated</dt>\n <dd><relative-time datetime=${open.card.updatedAt}></relative-time></dd>\n </div>\n `\n : nothing}\n </dl>\n </div>\n `\n : nothing}\n </popover-panel>\n `;\n }\n\n override render() {\n const indicator: Indicator | null = this._grab\n ? { columnId: this._grab.columnId, index: this._grab.index }\n : this._pointer;\n const dragCardId = this._grab?.cardId ?? this._drag?.cardId ?? null;\n return html`\n <div\n class=\"board\"\n role=\"group\"\n aria-label=${this.label}\n @dragend=${() => this.#onDragEnd()}\n >\n ${repeat(this._cols, (column) => column.id, (column) =>\n this.#renderColumn(column, indicator, dragCardId),\n )}\n </div>\n <div class=\"sr-only\" role=\"status\" aria-live=\"polite\">${this._liveMessage}</div>\n ${this.#renderDetail()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"kanban-board\": KanbanBoard;\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * A single kanban card's compact overview: its ticket number and title only.
4
+ * Purely presentational and metadata-only — it is created and driven by
5
+ * `kanban-board`, which owns drag-and-drop, selection, and the richer detail
6
+ * view (description, state, and timestamps live in the board's popover, not
7
+ * here). The board sets `draggable`, toggles the `dragging`/`grabbed`
8
+ * attributes for pointer and keyboard moves, and binds the open/keyboard
9
+ * handlers; focus is delegated to the inner control so the board can move
10
+ * keyboard focus to a card after a move.
11
+ *
12
+ * @element kanban-card
13
+ */
14
+ export declare class KanbanCard extends LitElement {
15
+ static shadowRootOptions: {
16
+ clonable?: boolean;
17
+ customElementRegistry?: CustomElementRegistry | null;
18
+ mode: ShadowRootMode;
19
+ serializable?: boolean;
20
+ slotAssignment?: SlotAssignmentMode;
21
+ delegatesFocus: boolean;
22
+ };
23
+ /** Ticket identifier shown before the title, e.g. `"PROJ-142"`. */
24
+ ticket: string;
25
+ /** Card title shown in the overview. */
26
+ heading: string;
27
+ static styles: import("lit").CSSResult[];
28
+ render(): import("lit-html").TemplateResult<1>;
29
+ }
30
+ declare global {
31
+ interface HTMLElementTagNameMap {
32
+ "kanban-card": KanbanCard;
33
+ }
34
+ }
35
+ //# sourceMappingURL=kanban-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanban-card.d.ts","sourceRoot":"","sources":["../src/kanban-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,KAAK,CAAC;AAK5C;;;;;;;;;;;GAWG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,OAAgB,iBAAiB;;;;;;;MAG/B;IAEF,mEAAmE;IACvD,MAAM,SAAM;IACxB,wCAAwC;IAC5B,OAAO,SAAM;IAEzB,OAAgB,MAAM,4BAwGpB;IAEO,MAAM,yCAWd;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,UAAU,CAAC;KAC3B;CACF"}
@@ -0,0 +1,163 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, css, html } from "lit";
8
+ import { customElement, property } from "lit/decorators.js";
9
+ import { iconTag } from "./icons.js";
10
+ import { tokens } from "./tokens.js";
11
+ /**
12
+ * A single kanban card's compact overview: its ticket number and title only.
13
+ * Purely presentational and metadata-only — it is created and driven by
14
+ * `kanban-board`, which owns drag-and-drop, selection, and the richer detail
15
+ * view (description, state, and timestamps live in the board's popover, not
16
+ * here). The board sets `draggable`, toggles the `dragging`/`grabbed`
17
+ * attributes for pointer and keyboard moves, and binds the open/keyboard
18
+ * handlers; focus is delegated to the inner control so the board can move
19
+ * keyboard focus to a card after a move.
20
+ *
21
+ * @element kanban-card
22
+ */
23
+ let KanbanCard = class KanbanCard extends LitElement {
24
+ constructor() {
25
+ super(...arguments);
26
+ /** Ticket identifier shown before the title, e.g. `"PROJ-142"`. */
27
+ this.ticket = "";
28
+ /** Card title shown in the overview. */
29
+ this.heading = "";
30
+ }
31
+ static { this.shadowRootOptions = {
32
+ ...LitElement.shadowRootOptions,
33
+ delegatesFocus: true,
34
+ }; }
35
+ static { this.styles = [
36
+ tokens,
37
+ css `
38
+ :host {
39
+ display: block;
40
+ }
41
+ .card {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: 0.25rem;
45
+ width: 100%;
46
+ box-sizing: border-box;
47
+ padding: 0.5rem 0.75rem;
48
+ background: var(--ui-surface, #ffffff);
49
+ border: 1px solid var(--ui-border, #e2e8f0);
50
+ border-radius: var(--ui-radius, 0.5rem);
51
+ cursor: grab;
52
+ text-align: left;
53
+ font-family: var(
54
+ --ui-font,
55
+ ui-sans-serif,
56
+ system-ui,
57
+ sans-serif,
58
+ "Apple Color Emoji",
59
+ "Segoe UI Emoji",
60
+ "Segoe UI Symbol",
61
+ "Noto Color Emoji"
62
+ );
63
+ transition:
64
+ box-shadow 150ms ease,
65
+ border-color 150ms ease;
66
+ }
67
+ .card:hover {
68
+ border-color: var(--ui-text-muted, #64748b);
69
+ box-shadow: var(
70
+ --ui-shadow,
71
+ 0 4px 6px -1px rgb(0 0 0 / 0.1),
72
+ 0 2px 4px -2px rgb(0 0 0 / 0.1)
73
+ );
74
+ }
75
+ .card:active {
76
+ cursor: grabbing;
77
+ }
78
+ .card:focus-visible {
79
+ outline: none;
80
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
81
+ }
82
+ .ticket {
83
+ display: inline-flex;
84
+ align-items: center;
85
+ gap: 0.25rem;
86
+ font-size: var(--ui-font-size-sm, 0.75rem);
87
+ font-weight: var(--ui-font-weight-medium, 500);
88
+ color: var(--ui-text-muted, #64748b);
89
+ }
90
+ .ticket-icon {
91
+ display: inline-flex;
92
+ line-height: 0;
93
+ }
94
+ .title {
95
+ font-size: var(--ui-font-size, 0.875rem);
96
+ font-weight: var(--ui-font-weight-medium, 500);
97
+ line-height: var(--ui-line-height-tight, 1.25);
98
+ color: var(--ui-text, #0f172a);
99
+ }
100
+ :host([dragging]) .card {
101
+ opacity: 0.5;
102
+ cursor: grabbing;
103
+ }
104
+ :host([grabbed]) .card {
105
+ cursor: grabbing;
106
+ border-color: var(--ui-primary, #4f46e5);
107
+ box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));
108
+ }
109
+ @keyframes kb-just-moved {
110
+ 0%,
111
+ 25% {
112
+ background-color: var(--ui-highlight, #fde68a);
113
+ }
114
+ 100% {
115
+ background-color: var(--ui-surface, #ffffff);
116
+ }
117
+ }
118
+ :host([just-moved]) .card {
119
+ animation: kb-just-moved 1400ms ease-out;
120
+ }
121
+ @media (forced-colors: active) {
122
+ .card:focus-visible,
123
+ :host([grabbed]) .card {
124
+ outline: 2px solid CanvasText;
125
+ outline-offset: 2px;
126
+ box-shadow: none;
127
+ }
128
+ }
129
+ @media (prefers-reduced-motion: reduce) {
130
+ .card {
131
+ transition: none;
132
+ }
133
+ :host([just-moved]) .card {
134
+ animation: none;
135
+ background-color: var(--ui-highlight, #fde68a);
136
+ }
137
+ }
138
+ `,
139
+ ]; }
140
+ render() {
141
+ const label = this.ticket ? `${this.ticket}: ${this.heading}` : this.heading;
142
+ return html `
143
+ <div class="card" role="button" tabindex="0" aria-label=${label}>
144
+ <span class="ticket">
145
+ <span class="ticket-icon" aria-hidden="true">${iconTag(14)}</span>
146
+ ${this.ticket}
147
+ </span>
148
+ <span class="title">${this.heading}</span>
149
+ </div>
150
+ `;
151
+ }
152
+ };
153
+ __decorate([
154
+ property()
155
+ ], KanbanCard.prototype, "ticket", void 0);
156
+ __decorate([
157
+ property()
158
+ ], KanbanCard.prototype, "heading", void 0);
159
+ KanbanCard = __decorate([
160
+ customElement("kanban-card")
161
+ ], KanbanCard);
162
+ export { KanbanCard };
163
+ //# sourceMappingURL=kanban-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanban-card.js","sourceRoot":"","sources":["../src/kanban-card.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;;GAWG;AAEI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,UAAU;IAAnC;;QAML,mEAAmE;QACvD,WAAM,GAAG,EAAE,CAAC;QACxB,wCAAwC;QAC5B,YAAO,GAAG,EAAE,CAAC;IAwH3B,CAAC;aAhIiB,sBAAiB,GAAG;QAClC,GAAG,UAAU,CAAC,iBAAiB;QAC/B,cAAc,EAAE,IAAI;KACrB,AAHgC,CAG/B;aAOc,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqGF;KACF,AAxGqB,CAwGpB;IAEO,MAAM;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;QAC7E,OAAO,IAAI,CAAA;gEACiD,KAAK;;yDAEZ,OAAO,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,MAAM;;8BAEO,IAAI,CAAC,OAAO;;KAErC,CAAC;IACJ,CAAC;CACF,CAAA;AA1Ha;IAAX,QAAQ,EAAE;0CAAa;AAEZ;IAAX,QAAQ,EAAE;2CAAc;AATd,UAAU;IADtB,aAAa,CAAC,aAAa,CAAC;GAChB,UAAU,CAiItB","sourcesContent":["import { LitElement, css, html } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconTag } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A single kanban card's compact overview: its ticket number and title only.\n * Purely presentational and metadata-only — it is created and driven by\n * `kanban-board`, which owns drag-and-drop, selection, and the richer detail\n * view (description, state, and timestamps live in the board's popover, not\n * here). The board sets `draggable`, toggles the `dragging`/`grabbed`\n * attributes for pointer and keyboard moves, and binds the open/keyboard\n * handlers; focus is delegated to the inner control so the board can move\n * keyboard focus to a card after a move.\n *\n * @element kanban-card\n */\n@customElement(\"kanban-card\")\nexport class KanbanCard extends LitElement {\n static override shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n /** Ticket identifier shown before the title, e.g. `\"PROJ-142\"`. */\n @property() ticket = \"\";\n /** Card title shown in the overview. */\n @property() heading = \"\";\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n }\n .card {\n display: flex;\n flex-direction: column;\n gap: 0.25rem;\n width: 100%;\n box-sizing: border-box;\n padding: 0.5rem 0.75rem;\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n cursor: grab;\n text-align: left;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n transition:\n box-shadow 150ms ease,\n border-color 150ms ease;\n }\n .card:hover {\n border-color: var(--ui-text-muted, #64748b);\n box-shadow: var(\n --ui-shadow,\n 0 4px 6px -1px rgb(0 0 0 / 0.1),\n 0 2px 4px -2px rgb(0 0 0 / 0.1)\n );\n }\n .card:active {\n cursor: grabbing;\n }\n .card:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .ticket {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n color: var(--ui-text-muted, #64748b);\n }\n .ticket-icon {\n display: inline-flex;\n line-height: 0;\n }\n .title {\n font-size: var(--ui-font-size, 0.875rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text, #0f172a);\n }\n :host([dragging]) .card {\n opacity: 0.5;\n cursor: grabbing;\n }\n :host([grabbed]) .card {\n cursor: grabbing;\n border-color: var(--ui-primary, #4f46e5);\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @keyframes kb-just-moved {\n 0%,\n 25% {\n background-color: var(--ui-highlight, #fde68a);\n }\n 100% {\n background-color: var(--ui-surface, #ffffff);\n }\n }\n :host([just-moved]) .card {\n animation: kb-just-moved 1400ms ease-out;\n }\n @media (forced-colors: active) {\n .card:focus-visible,\n :host([grabbed]) .card {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .card {\n transition: none;\n }\n :host([just-moved]) .card {\n animation: none;\n background-color: var(--ui-highlight, #fde68a);\n }\n }\n `,\n ];\n\n override render() {\n const label = this.ticket ? `${this.ticket}: ${this.heading}` : this.heading;\n return html`\n <div class=\"card\" role=\"button\" tabindex=\"0\" aria-label=${label}>\n <span class=\"ticket\">\n <span class=\"ticket-icon\" aria-hidden=\"true\">${iconTag(14)}</span>\n ${this.ticket}\n </span>\n <span class=\"title\">${this.heading}</span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"kanban-card\": KanbanCard;\n }\n}\n"]}
@@ -0,0 +1,30 @@
1
+ import { LitElement } from "lit";
2
+ /**
3
+ * A single kanban column: a titled, vertically scrollable region that holds
4
+ * its `kanban-card` children (its default `<slot>`), with a header showing the
5
+ * column title and card count. Purely presentational and metadata-only —
6
+ * `kanban-board` creates it, positions the cards inside it, and drives the
7
+ * drop-target highlight via the reflected `dragover` attribute and the empty
8
+ * hint via `empty`.
9
+ *
10
+ * @element kanban-column
11
+ * @slot - The column's `kanban-card` elements, in display order.
12
+ */
13
+ export declare class KanbanColumn extends LitElement {
14
+ /** Column title shown in the header. */
15
+ heading: string;
16
+ /** Number of cards in the column, shown as a count badge. */
17
+ count: number;
18
+ /** Set by the board while a card is dragged over this column, for highlight. */
19
+ dragover: boolean;
20
+ /** Whether the column currently has no cards, so it renders an empty hint. */
21
+ empty: boolean;
22
+ static styles: import("lit").CSSResult[];
23
+ render(): import("lit-html").TemplateResult<1>;
24
+ }
25
+ declare global {
26
+ interface HTMLElementTagNameMap {
27
+ "kanban-column": KanbanColumn;
28
+ }
29
+ }
30
+ //# sourceMappingURL=kanban-column.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanban-column.d.ts","sourceRoot":"","sources":["../src/kanban-column.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAIrD;;;;;;;;;;GAUG;AACH,qBACa,YAAa,SAAQ,UAAU;IAC1C,wCAAwC;IAC5B,OAAO,SAAM;IACzB,6DAA6D;IACjC,KAAK,SAAK;IACtC,gFAAgF;IACpC,QAAQ,UAAS;IAC7D,8EAA8E;IAClC,KAAK,UAAS;IAE1D,OAAgB,MAAM,4BAqGpB;IAEO,MAAM,yCAad;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,eAAe,EAAE,YAAY,CAAC;KAC/B;CACF"}
@@ -0,0 +1,166 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { LitElement, css, html, nothing } from "lit";
8
+ import { customElement, property } from "lit/decorators.js";
9
+ import { tokens } from "./tokens.js";
10
+ /**
11
+ * A single kanban column: a titled, vertically scrollable region that holds
12
+ * its `kanban-card` children (its default `<slot>`), with a header showing the
13
+ * column title and card count. Purely presentational and metadata-only —
14
+ * `kanban-board` creates it, positions the cards inside it, and drives the
15
+ * drop-target highlight via the reflected `dragover` attribute and the empty
16
+ * hint via `empty`.
17
+ *
18
+ * @element kanban-column
19
+ * @slot - The column's `kanban-card` elements, in display order.
20
+ */
21
+ let KanbanColumn = class KanbanColumn extends LitElement {
22
+ constructor() {
23
+ super(...arguments);
24
+ /** Column title shown in the header. */
25
+ this.heading = "";
26
+ /** Number of cards in the column, shown as a count badge. */
27
+ this.count = 0;
28
+ /** Set by the board while a card is dragged over this column, for highlight. */
29
+ this.dragover = false;
30
+ /** Whether the column currently has no cards, so it renders an empty hint. */
31
+ this.empty = false;
32
+ }
33
+ static { this.styles = [
34
+ tokens,
35
+ css `
36
+ :host {
37
+ display: flex;
38
+ flex-direction: column;
39
+ flex: 0 0 18rem;
40
+ min-height: 0;
41
+ max-height: 100%;
42
+ font-family: var(
43
+ --ui-font,
44
+ ui-sans-serif,
45
+ system-ui,
46
+ sans-serif,
47
+ "Apple Color Emoji",
48
+ "Segoe UI Emoji",
49
+ "Segoe UI Symbol",
50
+ "Noto Color Emoji"
51
+ );
52
+ }
53
+ .column {
54
+ display: flex;
55
+ flex-direction: column;
56
+ min-height: 0;
57
+ max-height: 100%;
58
+ background: var(--ui-surface-muted, #f8fafc);
59
+ border: 1px solid var(--ui-border, #e2e8f0);
60
+ border-radius: var(--ui-radius, 0.5rem);
61
+ transition: border-color 150ms ease;
62
+ }
63
+ .header {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-between;
67
+ gap: 0.5rem;
68
+ padding: 0.75rem;
69
+ border-bottom: 1px solid var(--ui-border, #e2e8f0);
70
+ flex: 0 0 auto;
71
+ }
72
+ .heading {
73
+ font-size: var(--ui-font-size, 0.875rem);
74
+ font-weight: var(--ui-font-weight-semibold, 600);
75
+ line-height: var(--ui-line-height-tight, 1.25);
76
+ color: var(--ui-text, #0f172a);
77
+ overflow: hidden;
78
+ white-space: nowrap;
79
+ text-overflow: ellipsis;
80
+ }
81
+ .count {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ min-width: 1.25rem;
86
+ height: 1.25rem;
87
+ padding: 0 0.25rem;
88
+ box-sizing: border-box;
89
+ background: var(--ui-surface, #ffffff);
90
+ border: 1px solid var(--ui-border, #e2e8f0);
91
+ border-radius: 999px;
92
+ font-size: var(--ui-font-size-xs, 0.6875rem);
93
+ font-weight: var(--ui-font-weight-medium, 500);
94
+ line-height: var(--ui-line-height-glyph, 1);
95
+ color: var(--ui-text-muted, #64748b);
96
+ flex: 0 0 auto;
97
+ }
98
+ .cards {
99
+ display: flex;
100
+ flex-direction: column;
101
+ gap: 0.5rem;
102
+ padding: 0.75rem;
103
+ overflow-y: auto;
104
+ flex: 1 1 auto;
105
+ min-height: 3rem;
106
+ }
107
+ .empty {
108
+ margin: 0;
109
+ padding: 0.75rem;
110
+ text-align: center;
111
+ font-size: var(--ui-font-size-sm, 0.75rem);
112
+ color: var(--ui-text-muted, #64748b);
113
+ border: 1px dashed var(--ui-border, #e2e8f0);
114
+ border-radius: var(--ui-radius-sm, 0.25rem);
115
+ }
116
+ :host([dragover]) .column {
117
+ border-color: var(--ui-primary, #4f46e5);
118
+ }
119
+ :host([dragover]) .cards {
120
+ background: color-mix(in srgb, var(--ui-primary, #4f46e5) 6%, transparent);
121
+ }
122
+ @media (forced-colors: active) {
123
+ :host([dragover]) .column {
124
+ outline: 2px solid Highlight;
125
+ outline-offset: -2px;
126
+ }
127
+ }
128
+ @media (prefers-reduced-motion: reduce) {
129
+ .column {
130
+ transition: none;
131
+ }
132
+ }
133
+ `,
134
+ ]; }
135
+ render() {
136
+ return html `
137
+ <section class="column" aria-label=${this.heading}>
138
+ <header class="header">
139
+ <span class="heading">${this.heading}</span>
140
+ <span class="count" aria-hidden="true">${this.count}</span>
141
+ </header>
142
+ <div class="cards">
143
+ <slot></slot>
144
+ ${this.empty ? html `<p class="empty">No cards</p>` : nothing}
145
+ </div>
146
+ </section>
147
+ `;
148
+ }
149
+ };
150
+ __decorate([
151
+ property()
152
+ ], KanbanColumn.prototype, "heading", void 0);
153
+ __decorate([
154
+ property({ type: Number })
155
+ ], KanbanColumn.prototype, "count", void 0);
156
+ __decorate([
157
+ property({ type: Boolean, reflect: true })
158
+ ], KanbanColumn.prototype, "dragover", void 0);
159
+ __decorate([
160
+ property({ type: Boolean, reflect: true })
161
+ ], KanbanColumn.prototype, "empty", void 0);
162
+ KanbanColumn = __decorate([
163
+ customElement("kanban-column")
164
+ ], KanbanColumn);
165
+ export { KanbanColumn };
166
+ //# sourceMappingURL=kanban-column.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kanban-column.js","sourceRoot":"","sources":["../src/kanban-column.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC;;;;;;;;;;GAUG;AAEI,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAArC;;QACL,wCAAwC;QAC5B,YAAO,GAAG,EAAE,CAAC;QACzB,6DAA6D;QACjC,UAAK,GAAG,CAAC,CAAC;QACtC,gFAAgF;QACpC,aAAQ,GAAG,KAAK,CAAC;QAC7D,8EAA8E;QAClC,UAAK,GAAG,KAAK,CAAC;IAuH5D,CAAC;aArHiB,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkGF;KACF,AArGqB,CAqGpB;IAEO,MAAM;QACb,OAAO,IAAI,CAAA;2CAC4B,IAAI,CAAC,OAAO;;kCAErB,IAAI,CAAC,OAAO;mDACK,IAAI,CAAC,KAAK;;;;YAIjD,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA,+BAA+B,CAAC,CAAC,CAAC,OAAO;;;KAGjE,CAAC;IACJ,CAAC;CACF,CAAA;AA7Ha;IAAX,QAAQ,EAAE;6CAAc;AAEG;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;2CAAW;AAEM;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;8CAAkB;AAEjB;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;2CAAe;AAR/C,YAAY;IADxB,aAAa,CAAC,eAAe,CAAC;GAClB,YAAY,CA+HxB","sourcesContent":["import { LitElement, css, html, nothing } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { tokens } from \"./tokens.js\";\n\n/**\n * A single kanban column: a titled, vertically scrollable region that holds\n * its `kanban-card` children (its default `<slot>`), with a header showing the\n * column title and card count. Purely presentational and metadata-only —\n * `kanban-board` creates it, positions the cards inside it, and drives the\n * drop-target highlight via the reflected `dragover` attribute and the empty\n * hint via `empty`.\n *\n * @element kanban-column\n * @slot - The column's `kanban-card` elements, in display order.\n */\n@customElement(\"kanban-column\")\nexport class KanbanColumn extends LitElement {\n /** Column title shown in the header. */\n @property() heading = \"\";\n /** Number of cards in the column, shown as a count badge. */\n @property({ type: Number }) count = 0;\n /** Set by the board while a card is dragged over this column, for highlight. */\n @property({ type: Boolean, reflect: true }) dragover = false;\n /** Whether the column currently has no cards, so it renders an empty hint. */\n @property({ type: Boolean, reflect: true }) empty = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: flex;\n flex-direction: column;\n flex: 0 0 18rem;\n min-height: 0;\n max-height: 100%;\n font-family: var(\n --ui-font,\n ui-sans-serif,\n system-ui,\n sans-serif,\n \"Apple Color Emoji\",\n \"Segoe UI Emoji\",\n \"Segoe UI Symbol\",\n \"Noto Color Emoji\"\n );\n }\n .column {\n display: flex;\n flex-direction: column;\n min-height: 0;\n max-height: 100%;\n background: var(--ui-surface-muted, #f8fafc);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n transition: border-color 150ms ease;\n }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n flex: 0 0 auto;\n }\n .heading {\n font-size: var(--ui-font-size, 0.875rem);\n font-weight: var(--ui-font-weight-semibold, 600);\n line-height: var(--ui-line-height-tight, 1.25);\n color: var(--ui-text, #0f172a);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n }\n .count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n height: 1.25rem;\n padding: 0 0.25rem;\n box-sizing: border-box;\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: 999px;\n font-size: var(--ui-font-size-xs, 0.6875rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-glyph, 1);\n color: var(--ui-text-muted, #64748b);\n flex: 0 0 auto;\n }\n .cards {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n padding: 0.75rem;\n overflow-y: auto;\n flex: 1 1 auto;\n min-height: 3rem;\n }\n .empty {\n margin: 0;\n padding: 0.75rem;\n text-align: center;\n font-size: var(--ui-font-size-sm, 0.75rem);\n color: var(--ui-text-muted, #64748b);\n border: 1px dashed var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n }\n :host([dragover]) .column {\n border-color: var(--ui-primary, #4f46e5);\n }\n :host([dragover]) .cards {\n background: color-mix(in srgb, var(--ui-primary, #4f46e5) 6%, transparent);\n }\n @media (forced-colors: active) {\n :host([dragover]) .column {\n outline: 2px solid Highlight;\n outline-offset: -2px;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n .column {\n transition: none;\n }\n }\n `,\n ];\n\n override render() {\n return html`\n <section class=\"column\" aria-label=${this.heading}>\n <header class=\"header\">\n <span class=\"heading\">${this.heading}</span>\n <span class=\"count\" aria-hidden=\"true\">${this.count}</span>\n </header>\n <div class=\"cards\">\n <slot></slot>\n ${this.empty ? html`<p class=\"empty\">No cards</p>` : nothing}\n </div>\n </section>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"kanban-column\": KanbanColumn;\n }\n}\n"]}