@f-ewald/components 1.1.1 → 1.2.1
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 +4 -0
- package/custom-elements.json +2336 -290
- package/dist/form-select.d.ts +5 -4
- package/dist/form-select.d.ts.map +1 -1
- package/dist/form-select.js +6 -5
- package/dist/form-select.js.map +1 -1
- package/dist/icons.d.ts +1 -0
- package/dist/icons.d.ts.map +1 -1
- package/dist/icons.js +1 -0
- package/dist/icons.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/kanban-board.d.ts +110 -0
- package/dist/kanban-board.d.ts.map +1 -0
- package/dist/kanban-board.js +619 -0
- package/dist/kanban-board.js.map +1 -0
- package/dist/kanban-card.d.ts +35 -0
- package/dist/kanban-card.d.ts.map +1 -0
- package/dist/kanban-card.js +163 -0
- package/dist/kanban-card.js.map +1 -0
- package/dist/kanban-column.d.ts +30 -0
- package/dist/kanban-column.d.ts.map +1 -0
- package/dist/kanban-column.js +166 -0
- package/dist/kanban-column.js.map +1 -0
- package/dist/multi-select.d.ts +142 -0
- package/dist/multi-select.d.ts.map +1 -0
- package/dist/multi-select.js +1304 -0
- package/dist/multi-select.js.map +1 -0
- package/dist/popover-panel.js +1 -1
- package/dist/popover-panel.js.map +1 -1
- package/dist/tokens.css +3 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +2 -0
- package/dist/tokens.js.map +1 -1
- package/docs/design-language.md +8 -0
- package/docs/form-select.md +5 -4
- package/docs/kanban-board.md +96 -0
- package/docs/kanban-card.md +56 -0
- package/docs/kanban-column.md +58 -0
- package/docs/multi-select.md +120 -0
- package/llms.txt +182 -4
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-select.js","sourceRoot":"","sources":["../src/multi-select.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n LitElement,\n css,\n html,\n nothing,\n type PropertyValues,\n type TemplateResult,\n} from \"lit\";\nimport { customElement, property, state } from \"lit/decorators.js\";\nimport { iconCheckCircle, iconChevronRight, iconX } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\n\nlet instanceCount = 0;\n\n/**\n * Presentation variant of {@link MultiSelect}.\n *\n * - `\"dropdown\"` (default): a compact trigger that opens a listbox popover.\n * - `\"list\"`: a persistently visible, bordered list surface with no popover.\n */\nexport type MultiSelectVariant = \"dropdown\" | \"list\";\n\n/** A single selectable option. */\nexport interface MultiSelectOption {\n value: string;\n label: string;\n /** Optional pre-rendered icon template displayed before the label. */\n icon?: TemplateResult;\n /** Square icon size in pixels. Defaults to 16 when `icon` is set. */\n iconSize?: number;\n /** When true, the option can neither be selected nor removed via the UI. */\n disabled?: boolean;\n}\n\n/**\n * A form-associated multi-select: a trigger showing a compact summary of the\n * current selection, opening a multi-selectable listbox popover, with an\n * optional removable-chip list of the chosen values. A drop-in generic\n * replacement for a native `<select multiple>` — set `name` on the element\n * itself and each\n * selected value is submitted as a repeated `name=value` entry, matching native\n * multiple-select semantics; `new FormData(form).getAll(name)` and\n * `form.reset()` work unchanged.\n *\n * The trigger visually follows `form-select`: a `2rem` field showing the\n * `placeholder` when empty, the single selected label when one value is chosen,\n * and `N selected` when several are. Set `show-chips` to additionally render\n * the selected values as compact chips below the trigger, each with an\n * accessible `32px` remove control; chips are off by default and the region\n * reserves no space while nothing is selected. Like `form-select`, the host is\n * `display: block` and fills its container by default; constrain the host\n * (`multi-select { display: inline-block; }`) to shrink it to its content\n * instead.\n *\n * Set `searchable` to replace the button trigger with an editable combobox that\n * infix-filters the predefined options by case-insensitive label. Typed text is\n * only a query: `values` changes exclusively when options are toggled, and an\n * uncommitted query is discarded when the list closes.\n *\n * The `variant` chooses between two presentations, and `searchable` applies to\n * both:\n *\n * - `\"dropdown\"` (default) is the popover form described above: a compact\n * trigger (button, or search combobox when `searchable`) that opens a\n * multi-selectable listbox on demand, closes on outside click / Escape, and\n * shows a chevron.\n * - `\"list\"` renders the options as a persistently visible, bordered surface\n * with no popover, no chevron, and no `open` host state; it never registers\n * outside-click listeners. Its scroll viewport is sized to roughly\n * `visibleRows` `2rem` rows (see `visible-rows`). When not `searchable` the\n * `listbox` itself is focusable and drives Arrow/Home/End/Enter/Space keyboard\n * navigation via `aria-activedescendant`; when `searchable` a `2rem` search\n * field sits above the list and owns navigation, and Escape only clears the\n * query instead of hiding the list.\n *\n * @element multi-select\n * @fires change - Fired with `{ values: string[] }` (a copied array) when a\n * value is added or removed through the UI. Programmatic `values` assignments\n * do not fire it.\n */\n@customElement(\"multi-select\")\nexport class MultiSelect extends LitElement {\n static formAssociated = true;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: block;\n position: relative;\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 font-size: var(--ui-font-size-sm, 0.75rem);\n }\n .control {\n position: relative;\n }\n button.trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.25rem;\n width: 100%;\n height: 2rem;\n box-sizing: border-box;\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 font-size: var(--ui-font-size-sm, 0.75rem);\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 background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n padding: 0.5rem 0.75rem;\n cursor: pointer;\n }\n button.trigger:hover:not(:disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n button.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n button.trigger:focus-visible {\n outline: none;\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 .trigger-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .trigger-label.placeholder {\n color: var(--ui-text-muted, #64748b);\n }\n .search-trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.25rem;\n width: 100%;\n height: 2rem;\n box-sizing: border-box;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n cursor: text;\n }\n .search-trigger:hover:not(.disabled) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .search-trigger:not(.disabled):focus-within {\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 .search-trigger.disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n input.search-input {\n min-width: 0;\n flex: 1;\n box-sizing: border-box;\n padding: 0.5rem 0 0.5rem 0.75rem;\n color: inherit;\n background: transparent;\n border: 0;\n outline: 0;\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 font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n }\n input.search-input::placeholder {\n color: var(--ui-text-muted, #64748b);\n font-weight: var(--ui-font-weight-medium, 500);\n opacity: 1;\n }\n .chevron {\n display: flex;\n flex: 0 0 auto;\n margin-right: 0.75rem;\n color: var(--ui-text-muted, #64748b);\n pointer-events: none;\n transform: rotate(90deg);\n transition: transform 150ms ease;\n }\n button.trigger .chevron {\n margin-right: 0;\n }\n :host([open]) .chevron {\n transform: rotate(-90deg);\n }\n ul.options {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 10;\n min-width: 100%;\n max-height: 40vh;\n overflow-y: auto;\n scrollbar-gutter: stable;\n margin: 0.25rem 0 0;\n padding: 0.25rem 0;\n list-style: none;\n white-space: nowrap;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n box-shadow: var(--ui-shadow, 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1));\n }\n ul.options::-webkit-scrollbar {\n width: 0.75rem;\n }\n ul.options::-webkit-scrollbar-thumb {\n background: var(--ui-border, #e2e8f0);\n border: 0.25rem solid transparent;\n border-radius: 999px;\n background-clip: padding-box;\n }\n .list-control {\n display: flex;\n flex-direction: column;\n }\n .search-field {\n display: flex;\n align-items: center;\n width: 100%;\n height: 2rem;\n box-sizing: border-box;\n margin-bottom: 0.25rem;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n cursor: text;\n }\n .search-field:not(.disabled):focus-within {\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 .search-field.disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n input.list-search {\n padding-right: 0.75rem;\n }\n ul.options.persistent {\n position: static;\n z-index: auto;\n min-width: 0;\n max-height: none;\n margin: 0;\n box-sizing: border-box;\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: none;\n }\n ul.options.persistent.disabled {\n cursor: not-allowed;\n opacity: 0.6;\n pointer-events: none;\n }\n ul.options.persistent:focus-visible {\n outline: none;\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 li {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.5rem 0.75rem;\n cursor: pointer;\n }\n li.active,\n li:hover:not([aria-disabled=\"true\"]) {\n background: var(--ui-surface-muted, #f8fafc);\n }\n li[aria-selected=\"true\"] {\n font-weight: var(--ui-font-weight-semibold, 600);\n color: var(--ui-primary, #4f46e5);\n }\n li[aria-disabled=\"true\"] {\n cursor: not-allowed;\n color: var(--ui-text-muted, #64748b);\n opacity: 0.6;\n }\n .check {\n display: inline-flex;\n flex: 0 0 auto;\n width: 14px;\n height: 14px;\n align-items: center;\n justify-content: center;\n color: var(--ui-primary, #4f46e5);\n }\n .check.hidden {\n visibility: hidden;\n }\n .check > svg {\n width: 100%;\n height: 100%;\n }\n .option-content {\n display: inline-flex;\n min-width: 0;\n flex: 1;\n align-items: center;\n gap: 0.5rem;\n }\n .option-icon {\n display: inline-flex;\n width: var(--multi-select-icon-size);\n height: var(--multi-select-icon-size);\n flex: 0 0 var(--multi-select-icon-size);\n align-items: center;\n justify-content: center;\n }\n .option-icon > svg {\n width: 100%;\n height: 100%;\n }\n .option-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n li.no-options {\n display: block;\n padding: 0.5rem 0.75rem;\n color: var(--ui-text-muted, #64748b);\n cursor: default;\n font-style: italic;\n }\n .chips {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n margin-top: 0.25rem;\n /* Pin the chips row to the control's resolved width (0 width +\n min-width 100%) so a long selected label ellipsizes instead of\n contributing its content width and widening the control. */\n width: 0;\n min-width: 100%;\n box-sizing: border-box;\n }\n .chip {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n max-width: 100%;\n box-sizing: border-box;\n padding-left: 0.5rem;\n color: var(--ui-text, #0f172a);\n background: var(--ui-surface-muted, #f8fafc);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius-sm, 0.25rem);\n }\n .chip-label {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: var(--ui-font-size-sm, 0.75rem);\n font-weight: var(--ui-font-weight-medium, 500);\n line-height: var(--ui-line-height-tight, 1.25);\n }\n .chip-remove {\n display: inline-flex;\n flex: 0 0 auto;\n width: 2rem;\n height: 2rem;\n align-items: center;\n justify-content: center;\n padding: 0;\n color: var(--ui-text-muted, #64748b);\n background: transparent;\n border: 0;\n border-radius: var(--ui-radius-sm, 0.25rem);\n cursor: pointer;\n }\n .chip-remove:hover:not(:disabled) {\n color: var(--ui-danger, #dc2626);\n }\n .chip-remove:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n }\n .chip-remove:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n .chip-remove > svg {\n width: 18px;\n height: 18px;\n }\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n @media (prefers-reduced-motion: reduce) {\n .chevron {\n transition: none;\n }\n }\n @media (forced-colors: active) {\n button.trigger:focus-visible,\n .search-trigger:not(.disabled):focus-within,\n .search-field:not(.disabled):focus-within,\n ul.options.persistent:focus-visible,\n .chip-remove:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n button.trigger:disabled,\n .search-trigger.disabled,\n .search-field.disabled,\n ul.options.persistent.disabled,\n .chip-remove:disabled,\n li[aria-disabled=\"true\"] {\n color: GrayText;\n opacity: 1;\n }\n li.active,\n li:hover:not([aria-disabled=\"true\"]) {\n color: HighlightText;\n background: Highlight;\n }\n li[aria-selected=\"true\"] {\n color: Highlight;\n }\n li.active[aria-selected=\"true\"],\n li[aria-selected=\"true\"]:hover {\n color: HighlightText;\n }\n .chip {\n border-color: CanvasText;\n }\n }\n `,\n ];\n\n /** The full list of selectable options. */\n @property({ attribute: false }) options: MultiSelectOption[] = [];\n /**\n * The currently selected values. Programmatic assignments are deduplicated\n * while preserving order and never fire `change`.\n */\n @property({ attribute: false }) values: string[] = [];\n /** Form control name; each selected value submits under it. */\n @property() name = \"\";\n /** Accessible label applied to the trigger. */\n @property() label = \"\";\n /** Text shown on the trigger when nothing is selected. */\n @property() placeholder = \"Select options\";\n /** Disables the whole control, preventing the popover from opening. */\n @property({ type: Boolean }) disabled = false;\n /** Marks the control as required for native form validation. */\n @property({ type: Boolean }) required = false;\n /**\n * Enables editable, case-insensitive infix filtering by option label.\n * Typed text never becomes a selected value.\n */\n @property({ type: Boolean, reflect: true }) searchable = false;\n /** Maximum number of selectable values; `0` (default) means unlimited. */\n @property({ type: Number }) max = 0;\n /**\n * Presentation variant. `\"dropdown\"` (default) opens a popover listbox;\n * `\"list\"` renders a persistently visible, bordered list surface. Reflected\n * so consumers can style by `[variant=\"list\"]`.\n */\n @property({ reflect: true }) variant: MultiSelectVariant = \"dropdown\";\n /**\n * Number of `2rem` rows the `list` variant's scroll viewport shows before it\n * scrolls, mirroring a native `<select size>`. Normalized to an integer of at\n * least `1` (default `5`); ignored by the `dropdown` variant.\n */\n @property({ type: Number, attribute: \"visible-rows\" }) visibleRows = 5;\n /**\n * When true, the selected values are also rendered as removable chips below\n * the trigger, each with an accessible `32px` remove control. Off by default:\n * the trigger already summarizes the selection, and values can be toggled off\n * in the listbox. Applies to both variants.\n */\n @property({ type: Boolean, attribute: \"show-chips\" }) showChips = false;\n\n @state() private _open = false;\n @state() private _activeIndex = -1;\n @state() private _query: string | null = null;\n @state() private _formDisabled = false;\n\n #internals = this.attachInternals();\n #defaultValues: string[] | null = null;\n #listboxPointerDown = false;\n #suppressNextBlur = false;\n #restoringSearchFocus = false;\n #searchSelection: [number | null, number | null] | null = null;\n #isComposing = false;\n #compositionJustEnded = false;\n #compositionEndTimer: ReturnType<typeof setTimeout> | null = null;\n #blurTimer: ReturnType<typeof setTimeout> | null = null;\n readonly #listboxId = `multi-select-listbox-${++instanceCount}`;\n\n /** Whether the host or an ancestor fieldset currently disables the control. */\n get #isDisabled(): boolean {\n return this.disabled || this._formDisabled;\n }\n\n /** `visibleRows` normalized to a whole number of rows, at least `1`. */\n get #rows(): number {\n const raw = this.visibleRows;\n if (!Number.isFinite(raw)) return 5;\n const floored = Math.floor(raw);\n return floored < 1 ? 1 : floored;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#blurTimer = null;\n this.#compositionEndTimer = null;\n this.#listboxPointerDown = false;\n this.#suppressNextBlur = false;\n this.#searchSelection = null;\n this.#isComposing = false;\n this.#compositionJustEnded = false;\n this.#close();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n if (!this.hasUpdated && this.#defaultValues === null) {\n this.#defaultValues = this.#dedupe(this.values);\n }\n if (changed.has(\"values\")) {\n const deduped = this.#dedupe(this.values);\n if (\n deduped.length !== this.values.length ||\n deduped.some((value, index) => value !== this.values[index])\n ) {\n this.values = deduped;\n }\n }\n if (\n (changed.has(\"disabled\") || changed.has(\"searchable\") || changed.has(\"variant\")) &&\n (this.#isDisabled || changed.has(\"searchable\") || changed.has(\"variant\"))\n ) {\n this.#close();\n }\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"_open\")) {\n this.toggleAttribute(\"open\", this._open);\n if (this._open) {\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n } else {\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n }\n }\n if (changed.has(\"values\") || changed.has(\"name\")) this.#syncFormValue();\n if (\n changed.has(\"values\") ||\n changed.has(\"required\") ||\n changed.has(\"disabled\") ||\n changed.has(\"_formDisabled\")\n ) {\n this.#syncValidity();\n }\n if (\n (changed.has(\"_activeIndex\") || changed.has(\"_query\") || changed.has(\"options\")) &&\n (this._open || this.variant === \"list\") &&\n this._activeIndex >= 0\n ) {\n this.renderRoot\n .querySelector<HTMLElement>(`#${this.#listboxId}-option-${this._activeIndex}`)\n ?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n }\n }\n\n /** Restores the selection captured at first render, per the form contract. */\n formResetCallback(): void {\n this.values = this.#defaultValues ? [...this.#defaultValues] : [];\n this.#close();\n }\n\n /** Mirrors an ancestor fieldset's disabled state and closes the popover. */\n formDisabledCallback(disabled: boolean): void {\n this._formDisabled = disabled;\n if (disabled) this.#close();\n }\n\n /** Restores the selection from the saved form state on navigation/autofill. */\n formStateRestoreCallback(state: string | File | FormData | null): void {\n if (typeof state !== \"string\") return;\n try {\n const parsed: unknown = JSON.parse(state);\n if (Array.isArray(parsed)) {\n this.values = parsed.filter((item): item is string => typeof item === \"string\");\n }\n } catch {\n /* ignore malformed restore state */\n }\n }\n\n #syncFormValue(): void {\n const values = this.values;\n if (!this.name || values.length === 0) {\n this.#internals.setFormValue(null);\n return;\n }\n const data = new FormData();\n for (const value of values) data.append(this.name, value);\n this.#internals.setFormValue(data, JSON.stringify(values));\n }\n\n #syncValidity(): void {\n const anchor = this.#anchorElement();\n if (this.#isDisabled) {\n this.#internals.setValidity({});\n return;\n }\n if (this.required && this.values.length === 0) {\n this.#internals.setValidity(\n { valueMissing: true },\n \"Please select at least one option.\",\n anchor ?? undefined,\n );\n } else {\n this.#internals.setValidity({});\n }\n }\n\n #anchorElement(): HTMLElement | null {\n return this.renderRoot.querySelector<HTMLElement>(\n \"button.trigger, input.search-input, ul.persistent\",\n );\n }\n\n #dedupe(values: readonly string[]): string[] {\n const seen = new Set<string>();\n const result: string[] = [];\n for (const value of values) {\n if (seen.has(value)) continue;\n seen.add(value);\n result.push(value);\n }\n return result;\n }\n\n /** First option matching `value`, so duplicate values resolve deterministically. */\n #optionByValue(value: string): MultiSelectOption | undefined {\n return this.options.find((option) => option.value === value);\n }\n\n #labelFor(value: string): string {\n return this.#optionByValue(value)?.label ?? value;\n }\n\n #summaryText(): string {\n if (this.values.length === 0) return this.placeholder;\n if (this.values.length === 1) return this.#labelFor(this.values[0]);\n return `${this.values.length} selected`;\n }\n\n #liveText(): string {\n if (this.values.length === 0) return \"No options selected\";\n if (this.values.length === 1) return `${this.#labelFor(this.values[0])} selected`;\n return `${this.values.length} options selected`;\n }\n\n #visibleOptions(): MultiSelectOption[] {\n if (!this.searchable || this._query === null) return this.options;\n const needle = this._query.trim().toLocaleLowerCase();\n if (!needle) return this.options;\n return this.options.filter((option) =>\n option.label.toLocaleLowerCase().includes(needle),\n );\n }\n\n /** Whether `value` is currently at the selection cap and cannot be added. */\n #atCap(value: string): boolean {\n return (\n this.max > 0 && this.values.length >= this.max && !this.values.includes(value)\n );\n }\n\n #isOptionDisabled(option: MultiSelectOption): boolean {\n return Boolean(option.disabled) || this.#atCap(option.value) || this.#isDisabled;\n }\n\n #toggleOption(option: MultiSelectOption): void {\n if (this.#isDisabled || option.disabled) return;\n if (this.values.includes(option.value)) {\n this.#commit(this.values.filter((value) => value !== option.value));\n return;\n }\n if (this.#atCap(option.value)) return;\n this.#commit([...this.values, option.value]);\n }\n\n #removeValue(value: string): void {\n if (this.#isDisabled) return;\n if (!this.values.includes(value)) return;\n this.#commit(this.values.filter((existing) => existing !== value));\n }\n\n #commit(next: string[]): void {\n this.values = this.#dedupe(next);\n this.dispatchEvent(\n new CustomEvent(\"change\", {\n detail: { values: [...this.values] },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #onFocusOut = (e: FocusEvent): void => {\n if (this.#listboxPointerDown || this.#suppressNextBlur) return;\n const next = e.relatedTarget;\n // Focus leaving to body/null (e.g. a pointer press on a non-focusable\n // element inside the component) is handled by the outside-mousedown\n // listener; only a genuine Tab-out to another element closes here.\n if (!(next instanceof Node)) return;\n if (this === next || this.renderRoot.contains(next)) return;\n this.#close();\n };\n\n #toggle(): void {\n if (this.#isDisabled) return;\n if (this._open) this.#close();\n else this.#open();\n }\n\n #open(): void {\n if (this.#isDisabled) return;\n this._query = null;\n this._open = true;\n this._activeIndex = this.#initialActiveIndex();\n }\n\n #close(): void {\n this._open = false;\n this._query = null;\n this._activeIndex = -1;\n this.#searchSelection = null;\n }\n\n #initialActiveIndex(): number {\n const options = this.#visibleOptions();\n if (options.length === 0) return -1;\n if (this._query !== null) return 0;\n const selectedIndex = options.findIndex((option) =>\n this.values.includes(option.value),\n );\n return selectedIndex >= 0 ? selectedIndex : 0;\n }\n\n #moveActive(delta: number): void {\n const options = this.#visibleOptions();\n if (options.length === 0) return;\n const n = options.length;\n this._activeIndex = (this._activeIndex + delta + n) % n;\n }\n\n #toggleActive(): void {\n const options = this.#visibleOptions();\n const option = options[this._activeIndex] ?? options[0];\n if (option) this.#toggleOption(option);\n }\n\n #onTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\" || e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n if (!this._open) {\n this.#open();\n return;\n }\n if (e.key === \"ArrowDown\") this.#moveActive(1);\n else if (e.key === \"ArrowUp\") this.#moveActive(-1);\n else this.#toggleActive();\n } else if ((e.key === \"Home\" || e.key === \"End\") && this._open) {\n e.preventDefault();\n const options = this.#visibleOptions();\n this._activeIndex = e.key === \"Home\" ? 0 : options.length - 1;\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n }\n }\n\n #onSearchFocus(e: FocusEvent): void {\n if (this.#isDisabled) return;\n if (this.#blurTimer) {\n clearTimeout(this.#blurTimer);\n this.#blurTimer = null;\n }\n if (!this._open) this.#open();\n if (!this.#restoringSearchFocus) (e.currentTarget as HTMLInputElement).select();\n }\n\n #onSearchClick(): void {\n if (!this._open) this.#open();\n }\n\n #onSearchMousedown(e: MouseEvent): void {\n if (e.button !== 0) e.preventDefault();\n }\n\n /** Seeds the active option when the persistent (non-searchable) list focuses. */\n #onListFocus(): void {\n if (this.#isDisabled || this.searchable) return;\n if (this._activeIndex < 0) this._activeIndex = this.#initialActiveIndex();\n }\n\n /** Keyboard navigation for the focusable, non-searchable persistent list. */\n #onListKeydown(e: KeyboardEvent): void {\n if (this.#isDisabled || this.searchable) return;\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n if (this._activeIndex < 0) this._activeIndex = this.#initialActiveIndex();\n else this.#moveActive(e.key === \"ArrowDown\" ? 1 : -1);\n } else if (e.key === \"Home\" || e.key === \"End\") {\n e.preventDefault();\n const options = this.#visibleOptions();\n this._activeIndex = e.key === \"Home\" ? 0 : options.length - 1;\n } else if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n this.#toggleActive();\n }\n // Escape intentionally does nothing: the list is never hidden.\n }\n\n /** Infix-filters the persistent list as the searchable-list query changes. */\n #onListSearchInput(e: InputEvent): void {\n this._query = (e.currentTarget as HTMLInputElement).value;\n const options = this.#visibleOptions();\n this._activeIndex = options.length > 0 ? 0 : -1;\n }\n\n /** Keyboard navigation for the search field above a searchable persistent list. */\n #onListSearchKeydown(e: KeyboardEvent): void {\n if (e.isComposing || e.keyCode === 229 || this.#isComposing || this.#compositionJustEnded) {\n return;\n }\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n this.#moveActive(e.key === \"ArrowDown\" ? 1 : -1);\n } else if (e.key === \"Home\" || e.key === \"End\") {\n e.preventDefault();\n const options = this.#visibleOptions();\n this._activeIndex = e.key === \"Home\" ? 0 : options.length - 1;\n } else if (e.key === \"Enter\") {\n e.preventDefault();\n this.#toggleActive();\n } else if (e.key === \"Escape\") {\n e.preventDefault();\n this._query = null;\n const options = this.#visibleOptions();\n this._activeIndex = options.length > 0 ? 0 : -1;\n } else if (\n e.key === \"Backspace\" &&\n (e.currentTarget as HTMLInputElement).value === \"\" &&\n this.values.length > 0\n ) {\n e.preventDefault();\n this.#removeValue(this.values[this.values.length - 1]);\n }\n }\n\n #onSearchInput(e: InputEvent): void {\n this._query = (e.currentTarget as HTMLInputElement).value;\n this._open = true;\n const options = this.#visibleOptions();\n this._activeIndex = options.length > 0 ? 0 : -1;\n }\n\n #onSearchKeydown(e: KeyboardEvent): void {\n if (e.isComposing || e.keyCode === 229 || this.#isComposing || this.#compositionJustEnded) {\n return;\n }\n if (e.key === \"ArrowDown\" || e.key === \"ArrowUp\") {\n e.preventDefault();\n if (!this._open) {\n this.#open();\n return;\n }\n this.#moveActive(e.key === \"ArrowDown\" ? 1 : -1);\n } else if ((e.key === \"Home\" || e.key === \"End\") && this._open) {\n e.preventDefault();\n const options = this.#visibleOptions();\n this._activeIndex = e.key === \"Home\" ? 0 : options.length - 1;\n } else if (e.key === \"Enter\" && this._open) {\n e.preventDefault();\n this.#toggleActive();\n } else if (e.key === \"Escape\" && this._open) {\n e.preventDefault();\n this.#close();\n } else if (\n e.key === \"Backspace\" &&\n (e.currentTarget as HTMLInputElement).value === \"\" &&\n this.values.length > 0\n ) {\n e.preventDefault();\n this.#removeValue(this.values[this.values.length - 1]);\n }\n }\n\n #onSearchBlur(): void {\n if (this.#blurTimer) clearTimeout(this.#blurTimer);\n this.#blurTimer = setTimeout(() => {\n this.#blurTimer = null;\n if (!this._open) return;\n if (!this.#listboxPointerDown && !this.#suppressNextBlur) this.#close();\n });\n }\n\n #focusSearchInput(e: MouseEvent): void {\n if (\n e.button !== 0 ||\n this.#isDisabled ||\n e.composedPath()[0] instanceof HTMLInputElement\n ) {\n return;\n }\n e.preventDefault();\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (!this._open) this.#open();\n input?.focus();\n input?.select();\n }\n\n #onCompositionStart(): void {\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = null;\n this.#compositionJustEnded = false;\n this.#isComposing = true;\n }\n\n #onCompositionEnd(): void {\n this.#isComposing = false;\n this.#compositionJustEnded = true;\n if (this.#compositionEndTimer) clearTimeout(this.#compositionEndTimer);\n this.#compositionEndTimer = setTimeout(() => {\n this.#compositionJustEnded = false;\n this.#compositionEndTimer = null;\n });\n }\n\n #onListboxMousedown(e: MouseEvent): void {\n if (e.button !== 0) return;\n this.#listboxPointerDown = true;\n this.#suppressNextBlur = true;\n const input = this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n this.#searchSelection = input ? [input.selectionStart, input.selectionEnd] : null;\n window.addEventListener(\n \"mouseup\",\n () => {\n this.#listboxPointerDown = false;\n if (this._open) {\n const searchInput =\n this.renderRoot.querySelector<HTMLInputElement>(\"input.search-input\");\n if (searchInput) {\n this.#restoringSearchFocus = true;\n searchInput.focus({ preventScroll: true });\n this.#restoringSearchFocus = false;\n const [start, end] = this.#searchSelection ?? [null, null];\n if (start !== null && end !== null) searchInput.setSelectionRange(start, end);\n }\n }\n this.#searchSelection = null;\n setTimeout(() => {\n this.#suppressNextBlur = false;\n });\n },\n { capture: true, once: true },\n );\n }\n\n #onOptionMousedown(e: MouseEvent, option: MultiSelectOption): void {\n if (e.button !== 0) return;\n const optionElement = e.currentTarget as HTMLElement;\n const listbox = optionElement.parentElement;\n if (listbox) {\n const scrollbarWidth = listbox.offsetWidth - listbox.clientWidth;\n const bounds = listbox.getBoundingClientRect();\n const isRtl = getComputedStyle(listbox).direction === \"rtl\";\n const inScrollbarGutter = isRtl\n ? e.clientX <= bounds.left + scrollbarWidth\n : e.clientX >= bounds.right - scrollbarWidth;\n if (scrollbarWidth > 0 && inScrollbarGutter) return;\n }\n e.preventDefault();\n if (this.#isOptionDisabled(option)) return;\n this.#toggleOption(option);\n if (this.variant === \"list\" && !this.searchable && !this.#isDisabled) {\n this.renderRoot\n .querySelector<HTMLElement>(\"ul.persistent\")\n ?.focus({ preventScroll: true });\n }\n }\n\n #optionIconSize(option: MultiSelectOption): number {\n const size = option.iconSize ?? 16;\n return Number.isFinite(size) && size > 0 ? size : 16;\n }\n\n #renderOptionIcon(option: MultiSelectOption) {\n if (!option.icon) return nothing;\n return html`\n <span\n class=\"option-icon\"\n style=${`--multi-select-icon-size: ${this.#optionIconSize(option)}px`}\n aria-hidden=\"true\"\n >\n ${option.icon}\n </span>\n `;\n }\n\n /** The shared `<li role=\"option\">` items for both variants' listboxes. */\n private renderOptionItems(options: MultiSelectOption[]) {\n return html`\n ${options.map((option, index) => {\n const selected = this.values.includes(option.value);\n const disabled = this.#isOptionDisabled(option);\n return html`\n <li\n id=${`${this.#listboxId}-option-${index}`}\n role=\"option\"\n aria-selected=${selected}\n aria-disabled=${disabled ? \"true\" : nothing}\n class=${index === this._activeIndex ? \"active\" : \"\"}\n @mousedown=${(e: MouseEvent) => this.#onOptionMousedown(e, option)}\n >\n <span class=\"check ${selected ? \"\" : \"hidden\"}\" aria-hidden=\"true\">\n ${iconCheckCircle(14)}\n </span>\n <span class=\"option-content\">\n ${this.#renderOptionIcon(option)}\n <span class=\"option-label\">${option.label}</span>\n </span>\n </li>\n `;\n })}\n ${options.length === 0\n ? html`<li class=\"no-options\" role=\"presentation\">\n <span role=\"status\">No options found</span>\n </li>`\n : nothing}\n `;\n }\n\n private renderListbox() {\n if (!this._open) return nothing;\n const options = this.#visibleOptions();\n return html`\n <ul\n id=${this.#listboxId}\n class=\"options\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n aria-label=${this.label ? `${this.label} options` : \"Options\"}\n @mousedown=${(e: MouseEvent) => this.#onListboxMousedown(e)}\n >\n ${this.renderOptionItems(options)}\n </ul>\n `;\n }\n\n private renderChips() {\n if (!this.showChips || this.values.length === 0) return nothing;\n return html`\n <div class=\"chips\">\n ${this.values.map((value) => {\n const label = this.#labelFor(value);\n return html`\n <span class=\"chip\">\n <span class=\"chip-label\">${label}</span>\n <button\n type=\"button\"\n class=\"chip-remove\"\n aria-label=${`Remove ${label}`}\n ?disabled=${this.#isDisabled}\n @click=${() => this.#removeValue(value)}\n >\n ${iconX(18)}\n </button>\n </span>\n `;\n })}\n </div>\n `;\n }\n\n private renderSearchTrigger() {\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#listboxId}-option-${this._activeIndex}`\n : nothing;\n return html`\n <div\n class=\"search-trigger ${this.#isDisabled ? \"disabled\" : \"\"}\"\n @mousedown=${(e: MouseEvent) => this.#focusSearchInput(e)}\n >\n <input\n type=\"text\"\n class=\"search-input\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open}\n aria-controls=${this.#listboxId}\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || \"Select options\"}\n placeholder=${this.#summaryText()}\n autocomplete=\"off\"\n ?disabled=${this.#isDisabled}\n .value=${this._query ?? \"\"}\n @mousedown=${(e: MouseEvent) => this.#onSearchMousedown(e)}\n @focus=${(e: FocusEvent) => this.#onSearchFocus(e)}\n @click=${() => this.#onSearchClick()}\n @input=${(e: InputEvent) => this.#onSearchInput(e)}\n @compositionstart=${() => this.#onCompositionStart()}\n @compositionend=${() => this.#onCompositionEnd()}\n @keydown=${(e: KeyboardEvent) => this.#onSearchKeydown(e)}\n @blur=${() => this.#onSearchBlur()}\n />\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </div>\n `;\n }\n\n private renderButtonTrigger() {\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this.#listboxId}-option-${this._activeIndex}`\n : nothing;\n const empty = this.values.length === 0;\n return html`\n <button\n type=\"button\"\n class=\"trigger\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this._open}\n aria-controls=${this.#listboxId}\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || nothing}\n ?disabled=${this.#isDisabled}\n @click=${() => this.#toggle()}\n @keydown=${(e: KeyboardEvent) => this.#onTriggerKeydown(e)}\n >\n <span class=\"trigger-label ${empty ? \"placeholder\" : \"\"}\">${this.#summaryText()}</span>\n <span class=\"chevron\">${iconChevronRight(14)}</span>\n </button>\n `;\n }\n\n private renderListSearch() {\n const activeDescendant =\n this._activeIndex >= 0 ? `${this.#listboxId}-option-${this._activeIndex}` : nothing;\n return html`\n <div class=\"search-field ${this.#isDisabled ? \"disabled\" : \"\"}\">\n <input\n type=\"text\"\n class=\"search-input list-search\"\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-expanded=\"true\"\n aria-controls=${this.#listboxId}\n aria-activedescendant=${activeDescendant}\n aria-label=${this.label || \"Select options\"}\n placeholder=${this.#summaryText()}\n autocomplete=\"off\"\n ?disabled=${this.#isDisabled}\n .value=${this._query ?? \"\"}\n @input=${(e: InputEvent) => this.#onListSearchInput(e)}\n @compositionstart=${() => this.#onCompositionStart()}\n @compositionend=${() => this.#onCompositionEnd()}\n @keydown=${(e: KeyboardEvent) => this.#onListSearchKeydown(e)}\n />\n </div>\n `;\n }\n\n private renderPersistentList() {\n const options = this.#visibleOptions();\n const focusable = !this.searchable && !this.#isDisabled;\n const activeDescendant =\n !this.searchable && this._activeIndex >= 0 && options.length > 0\n ? `${this.#listboxId}-option-${this._activeIndex}`\n : nothing;\n return html`\n <ul\n id=${this.#listboxId}\n class=\"options persistent ${this.#isDisabled ? \"disabled\" : \"\"}\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n aria-label=${this.label ? `${this.label} options` : \"Options\"}\n aria-disabled=${this.#isDisabled ? \"true\" : nothing}\n tabindex=${focusable ? \"0\" : nothing}\n aria-activedescendant=${activeDescendant}\n style=${`height: calc(${this.#rows} * 2rem + 0.5rem + 2px)`}\n @mousedown=${(e: MouseEvent) => this.#onListboxMousedown(e)}\n @focus=${() => this.#onListFocus()}\n @keydown=${(e: KeyboardEvent) => this.#onListKeydown(e)}\n >\n ${this.renderOptionItems(options)}\n </ul>\n `;\n }\n\n private renderListVariant() {\n return html`\n <div class=\"control list-control\">\n ${this.searchable ? this.renderListSearch() : nothing}\n ${this.renderPersistentList()}\n </div>\n ${this.renderChips()}\n <span class=\"sr-only\" aria-live=\"polite\">${this.#liveText()}</span>\n `;\n }\n\n override render() {\n if (this.variant === \"list\") return this.renderListVariant();\n return html`\n <div class=\"control\" @focusout=${(e: FocusEvent) => this.#onFocusOut(e)}>\n ${this.searchable ? this.renderSearchTrigger() : this.renderButtonTrigger()}\n ${this.renderListbox()}\n </div>\n ${this.renderChips()}\n <span class=\"sr-only\" aria-live=\"polite\">${this.#liveText()}</span>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"multi-select\": MultiSelect;\n }\n}\n"]}
|
package/dist/popover-panel.js
CHANGED
|
@@ -116,7 +116,6 @@ let PopoverPanel = class PopoverPanel extends LitElement {
|
|
|
116
116
|
box-shadow: var(--ui-shadow-lg, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));
|
|
117
117
|
display: flex;
|
|
118
118
|
flex-direction: column;
|
|
119
|
-
overflow: hidden;
|
|
120
119
|
}
|
|
121
120
|
.panel-header {
|
|
122
121
|
display: flex;
|
|
@@ -124,6 +123,7 @@ let PopoverPanel = class PopoverPanel extends LitElement {
|
|
|
124
123
|
justify-content: space-between;
|
|
125
124
|
padding: 0.75rem;
|
|
126
125
|
border-bottom: 1px solid var(--ui-border, #e2e8f0);
|
|
126
|
+
border-radius: var(--ui-radius, 0.5rem) var(--ui-radius, 0.5rem) 0 0;
|
|
127
127
|
flex: 0 0 auto;
|
|
128
128
|
}
|
|
129
129
|
.panel-title {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"popover-panel.js","sourceRoot":"","sources":["../src/popover-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconX } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\nimport {\n activateLayer,\n claimEscape,\n deactivateLayer,\n isTopLayer,\n} from \"./utils/layer-stack.js\";\n\n/**\n * Generic anchored popover shell: a floating card positioned relative to its\n * nearest `position: relative` ancestor (place it next to its trigger button\n * inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge\n * drawer. Closes on outside click or Escape. Header chrome and close button\n * match `slide-panel`'s API (`heading`, `panel-close`) so either can be\n * swapped in for the other with no consumer-side changes beyond the wrapper.\n *\n * Set `centered` to render as a screen-centered modal with a translucent\n * backdrop instead of the default anchored placement.\n *\n * @element popover-panel\n * @fires panel-close - User clicked the close (✕) button, pressed Escape, or clicked outside/the backdrop.\n * @slot title - Overrides the plain `heading` text with custom markup.\n * @slot actions - Extra header controls (e.g. an icon+label link) rendered between the title and the close button.\n * @slot - Popover body content.\n */\n@customElement(\"popover-panel\")\nexport class PopoverPanel extends LitElement {\n /** Whether the popover is currently visible. */\n @property({ type: Boolean, reflect: true }) open = false;\n /** Title text shown in the popover header. */\n @property() heading = \"\";\n /** Render as a screen-centered modal with a backdrop instead of anchored placement. */\n @property({ type: Boolean, reflect: true }) centered = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: none;\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n z-index: var(--component-layer-z, 20);\n }\n :host([open]) {\n display: block;\n }\n :host([centered][open]) {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n z-index: var(--component-layer-z, 30);\n }\n :host([centered]) .panel {\n width: 25rem;\n }\n .panel {\n width: 20rem;\n max-width: calc(100vw - 2rem);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: var(--ui-shadow-lg, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n flex: 0 0 auto;\n }\n .panel-title {\n font-weight: var(--ui-font-weight-semibold, 600);\n font-size: var(--ui-font-size-lg, 1rem);\n line-height: var(--ui-line-height-tight, 1.25);\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 color: var(--ui-text, #0f172a);\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n padding-right: 0.5rem;\n }\n .panel-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 0 0 auto;\n margin-right: 0.25rem;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n width: 2rem;\n height: 2rem;\n padding: 0;\n color: var(--ui-text-muted, #64748b);\n border-radius: var(--ui-radius-sm, 0.25rem);\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n .close-btn:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .close-btn:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @media (forced-colors: active) {\n .close-btn:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n #modalActive = false;\n #previousFocus: HTMLElement | null = null;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n document.removeEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n deactivateLayer(this);\n if (this.#previousFocus?.isConnected) this.#previousFocus.focus();\n this.#previousFocus = null;\n this.#modalActive = false;\n this.open = false;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"open\")) {\n if (this.open) {\n activateLayer(this);\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.addEventListener(\"keydown\", this.#onWindowKeydown);\n } else {\n deactivateLayer(this);\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n }\n }\n\n const shouldBeModal = this.open && this.centered;\n if (shouldBeModal && !this.#modalActive) {\n this.#modalActive = true;\n this.#previousFocus = document.activeElement as HTMLElement | null;\n document.addEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n this.#focusInitial();\n } else if (!shouldBeModal && this.#modalActive) {\n this.#modalActive = false;\n document.removeEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n if (this.#previousFocus?.isConnected) this.#previousFocus.focus();\n this.#previousFocus = null;\n }\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!isTopLayer(this)) return;\n // In centered mode the host itself renders the backdrop, so a mousedown\n // landing directly on the host (not on .panel or its content) is a\n // backdrop click and must close like an outside click would.\n if (this.centered && e.target === this) {\n this.#close();\n return;\n }\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #onWindowKeydown = (e: KeyboardEvent): void => {\n if (!isTopLayer(this)) return;\n if (claimEscape(this, e)) {\n this.#close();\n return;\n }\n if (!this.centered || e.key !== \"Tab\") return;\n\n const focusable = this.#getFocusableElements();\n if (focusable.length === 0) {\n e.preventDefault();\n this.#focusInitial();\n return;\n }\n const active = (this.shadowRoot?.activeElement ?? document.activeElement) as HTMLElement | null;\n const index = focusable.indexOf(active as HTMLElement);\n if (e.shiftKey && index <= 0) {\n e.preventDefault();\n focusable.at(-1)?.focus();\n } else if (!e.shiftKey && index === focusable.length - 1) {\n e.preventDefault();\n focusable[0]?.focus();\n }\n };\n\n #onDocumentFocusIn = (event: FocusEvent): void => {\n if (!this.#modalActive || !isTopLayer(this) || event.composedPath().includes(this)) return;\n this.#focusInitial();\n };\n\n #getFocusableElements(): HTMLElement[] {\n const selector =\n \"a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex='-1'])\";\n const focusableInSlot = (slotSelector: string): HTMLElement[] => {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>(slotSelector);\n return (slot?.assignedElements({ flatten: true }) ?? []).flatMap((element) => [\n ...(element instanceof HTMLElement && element.matches(selector) ? [element] : []),\n ...Array.from(element.querySelectorAll<HTMLElement>(selector)),\n ]);\n };\n const close = this.shadowRoot?.querySelector<HTMLElement>(\".close-btn\");\n return [\n ...focusableInSlot('slot[name=\"title\"]'),\n ...focusableInSlot('slot[name=\"actions\"]'),\n ...(close ? [close] : []),\n ...focusableInSlot(\"slot:not([name])\"),\n ].filter((element) => !element.hasAttribute(\"hidden\"));\n }\n\n #focusInitial(): void {\n const autofocus = this.querySelector<HTMLElement>(\"[autofocus]\");\n const close = this.shadowRoot?.querySelector<HTMLElement>(\".close-btn\");\n const panel = this.shadowRoot?.querySelector<HTMLElement>(\".panel\");\n (autofocus ?? close ?? this.#getFocusableElements()[0] ?? panel)?.focus();\n }\n\n #close(): void {\n this.dispatchEvent(new CustomEvent(\"panel-close\", { bubbles: true, composed: true }));\n }\n\n override render() {\n const explicitLabel = this.getAttribute(\"aria-label\");\n return html`\n <div\n class=\"panel\"\n role=\"dialog\"\n aria-modal=${this.centered ? \"true\" : nothing}\n aria-label=${explicitLabel ?? nothing}\n aria-labelledby=${explicitLabel ? nothing : \"popover-title\"}\n tabindex=\"-1\"\n >\n <div class=\"panel-header\">\n <span id=\"popover-title\" class=\"panel-title\">\n <slot name=\"title\">${this.heading || (this.centered ? \"Dialog\" : \"Popover\")}</slot>\n </span>\n <span class=\"panel-actions\"><slot name=\"actions\"></slot></span>\n <button class=\"close-btn\" aria-label=\"Close popover\" @click=${() => this.#close()}>\n <span aria-hidden=\"true\">${iconX(18)}</span>\n </button>\n </div>\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"popover-panel\": PopoverPanel;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"popover-panel.js","sourceRoot":"","sources":["../src/popover-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, css, html, nothing, type PropertyValues } from \"lit\";\nimport { customElement, property } from \"lit/decorators.js\";\nimport { iconX } from \"./icons.js\";\nimport { tokens } from \"./tokens.js\";\nimport {\n activateLayer,\n claimEscape,\n deactivateLayer,\n isTopLayer,\n} from \"./utils/layer-stack.js\";\n\n/**\n * Generic anchored popover shell: a floating card positioned relative to its\n * nearest `position: relative` ancestor (place it next to its trigger button\n * inside such a wrapper), as opposed to `slide-panel`'s fixed screen-edge\n * drawer. Closes on outside click or Escape. Header chrome and close button\n * match `slide-panel`'s API (`heading`, `panel-close`) so either can be\n * swapped in for the other with no consumer-side changes beyond the wrapper.\n *\n * Set `centered` to render as a screen-centered modal with a translucent\n * backdrop instead of the default anchored placement.\n *\n * @element popover-panel\n * @fires panel-close - User clicked the close (✕) button, pressed Escape, or clicked outside/the backdrop.\n * @slot title - Overrides the plain `heading` text with custom markup.\n * @slot actions - Extra header controls (e.g. an icon+label link) rendered between the title and the close button.\n * @slot - Popover body content.\n */\n@customElement(\"popover-panel\")\nexport class PopoverPanel extends LitElement {\n /** Whether the popover is currently visible. */\n @property({ type: Boolean, reflect: true }) open = false;\n /** Title text shown in the popover header. */\n @property() heading = \"\";\n /** Render as a screen-centered modal with a backdrop instead of anchored placement. */\n @property({ type: Boolean, reflect: true }) centered = false;\n\n static override styles = [\n tokens,\n css`\n :host {\n display: none;\n position: absolute;\n top: calc(100% + 0.5rem);\n right: 0;\n z-index: var(--component-layer-z, 20);\n }\n :host([open]) {\n display: block;\n }\n :host([centered][open]) {\n position: fixed;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--ui-overlay, rgb(15 23 42 / 0.45));\n z-index: var(--component-layer-z, 30);\n }\n :host([centered]) .panel {\n width: 25rem;\n }\n .panel {\n width: 20rem;\n max-width: calc(100vw - 2rem);\n background: var(--ui-surface, #ffffff);\n border: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem);\n box-shadow: var(--ui-shadow-lg, 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1));\n display: flex;\n flex-direction: column;\n }\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem;\n border-bottom: 1px solid var(--ui-border, #e2e8f0);\n border-radius: var(--ui-radius, 0.5rem) var(--ui-radius, 0.5rem) 0 0;\n flex: 0 0 auto;\n }\n .panel-title {\n font-weight: var(--ui-font-weight-semibold, 600);\n font-size: var(--ui-font-size-lg, 1rem);\n line-height: var(--ui-line-height-tight, 1.25);\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 color: var(--ui-text, #0f172a);\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n padding-right: 0.5rem;\n }\n .panel-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex: 0 0 auto;\n margin-right: 0.25rem;\n }\n .close-btn {\n background: none;\n border: none;\n cursor: pointer;\n width: 2rem;\n height: 2rem;\n padding: 0;\n color: var(--ui-text-muted, #64748b);\n border-radius: var(--ui-radius-sm, 0.25rem);\n flex: 0 0 auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n }\n .close-btn:hover {\n background: var(--ui-surface-muted, #f8fafc);\n }\n .close-btn:focus-visible {\n outline: none;\n box-shadow: var(--ui-focus-ring, 0 0 0 3px rgb(79 70 229 / 0.35));\n }\n @media (forced-colors: active) {\n .close-btn:focus-visible {\n outline: 2px solid CanvasText;\n outline-offset: 2px;\n box-shadow: none;\n }\n }\n `,\n ];\n\n #modalActive = false;\n #previousFocus: HTMLElement | null = null;\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n document.removeEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n deactivateLayer(this);\n if (this.#previousFocus?.isConnected) this.#previousFocus.focus();\n this.#previousFocus = null;\n this.#modalActive = false;\n this.open = false;\n }\n\n protected override updated(changed: PropertyValues): void {\n if (changed.has(\"open\")) {\n if (this.open) {\n activateLayer(this);\n window.addEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.addEventListener(\"keydown\", this.#onWindowKeydown);\n } else {\n deactivateLayer(this);\n window.removeEventListener(\"mousedown\", this.#onWindowMousedown, true);\n window.removeEventListener(\"keydown\", this.#onWindowKeydown);\n }\n }\n\n const shouldBeModal = this.open && this.centered;\n if (shouldBeModal && !this.#modalActive) {\n this.#modalActive = true;\n this.#previousFocus = document.activeElement as HTMLElement | null;\n document.addEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n this.#focusInitial();\n } else if (!shouldBeModal && this.#modalActive) {\n this.#modalActive = false;\n document.removeEventListener(\"focusin\", this.#onDocumentFocusIn, true);\n if (this.#previousFocus?.isConnected) this.#previousFocus.focus();\n this.#previousFocus = null;\n }\n }\n\n #onWindowMousedown = (e: MouseEvent): void => {\n if (!isTopLayer(this)) return;\n // In centered mode the host itself renders the backdrop, so a mousedown\n // landing directly on the host (not on .panel or its content) is a\n // backdrop click and must close like an outside click would.\n if (this.centered && e.target === this) {\n this.#close();\n return;\n }\n if (!e.composedPath().includes(this)) this.#close();\n };\n\n #onWindowKeydown = (e: KeyboardEvent): void => {\n if (!isTopLayer(this)) return;\n if (claimEscape(this, e)) {\n this.#close();\n return;\n }\n if (!this.centered || e.key !== \"Tab\") return;\n\n const focusable = this.#getFocusableElements();\n if (focusable.length === 0) {\n e.preventDefault();\n this.#focusInitial();\n return;\n }\n const active = (this.shadowRoot?.activeElement ?? document.activeElement) as HTMLElement | null;\n const index = focusable.indexOf(active as HTMLElement);\n if (e.shiftKey && index <= 0) {\n e.preventDefault();\n focusable.at(-1)?.focus();\n } else if (!e.shiftKey && index === focusable.length - 1) {\n e.preventDefault();\n focusable[0]?.focus();\n }\n };\n\n #onDocumentFocusIn = (event: FocusEvent): void => {\n if (!this.#modalActive || !isTopLayer(this) || event.composedPath().includes(this)) return;\n this.#focusInitial();\n };\n\n #getFocusableElements(): HTMLElement[] {\n const selector =\n \"a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex='-1'])\";\n const focusableInSlot = (slotSelector: string): HTMLElement[] => {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>(slotSelector);\n return (slot?.assignedElements({ flatten: true }) ?? []).flatMap((element) => [\n ...(element instanceof HTMLElement && element.matches(selector) ? [element] : []),\n ...Array.from(element.querySelectorAll<HTMLElement>(selector)),\n ]);\n };\n const close = this.shadowRoot?.querySelector<HTMLElement>(\".close-btn\");\n return [\n ...focusableInSlot('slot[name=\"title\"]'),\n ...focusableInSlot('slot[name=\"actions\"]'),\n ...(close ? [close] : []),\n ...focusableInSlot(\"slot:not([name])\"),\n ].filter((element) => !element.hasAttribute(\"hidden\"));\n }\n\n #focusInitial(): void {\n const autofocus = this.querySelector<HTMLElement>(\"[autofocus]\");\n const close = this.shadowRoot?.querySelector<HTMLElement>(\".close-btn\");\n const panel = this.shadowRoot?.querySelector<HTMLElement>(\".panel\");\n (autofocus ?? close ?? this.#getFocusableElements()[0] ?? panel)?.focus();\n }\n\n #close(): void {\n this.dispatchEvent(new CustomEvent(\"panel-close\", { bubbles: true, composed: true }));\n }\n\n override render() {\n const explicitLabel = this.getAttribute(\"aria-label\");\n return html`\n <div\n class=\"panel\"\n role=\"dialog\"\n aria-modal=${this.centered ? \"true\" : nothing}\n aria-label=${explicitLabel ?? nothing}\n aria-labelledby=${explicitLabel ? nothing : \"popover-title\"}\n tabindex=\"-1\"\n >\n <div class=\"panel-header\">\n <span id=\"popover-title\" class=\"panel-title\">\n <slot name=\"title\">${this.heading || (this.centered ? \"Dialog\" : \"Popover\")}</slot>\n </span>\n <span class=\"panel-actions\"><slot name=\"actions\"></slot></span>\n <button class=\"close-btn\" aria-label=\"Close popover\" @click=${() => this.#close()}>\n <span aria-hidden=\"true\">${iconX(18)}</span>\n </button>\n </div>\n <slot></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"popover-panel\": PopoverPanel;\n }\n}\n"]}
|
package/dist/tokens.css
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
--ui-border: #e2e8f0;
|
|
16
16
|
--ui-surface: #ffffff;
|
|
17
17
|
--ui-surface-muted: #f8fafc;
|
|
18
|
+
--ui-highlight: #fde68a;
|
|
18
19
|
--ui-tooltip: #0f172a;
|
|
19
20
|
--ui-hover-overlay: rgb(255 255 255 / 0.32);
|
|
20
21
|
--ui-overlay: rgb(15 23 42 / 0.45);
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
--ui-border: #334155;
|
|
59
60
|
--ui-surface: #0f172a;
|
|
60
61
|
--ui-surface-muted: #1e293b;
|
|
62
|
+
--ui-highlight: #854d0e;
|
|
61
63
|
--ui-tooltip: #020617;
|
|
62
64
|
--ui-hover-overlay: rgb(255 255 255 / 0.12);
|
|
63
65
|
--ui-overlay: rgb(2 6 23 / 0.6);
|
|
@@ -82,6 +84,7 @@
|
|
|
82
84
|
--ui-border: #334155;
|
|
83
85
|
--ui-surface: #0f172a;
|
|
84
86
|
--ui-surface-muted: #1e293b;
|
|
87
|
+
--ui-highlight: #854d0e;
|
|
85
88
|
--ui-tooltip: #020617;
|
|
86
89
|
--ui-hover-overlay: rgb(255 255 255 / 0.12);
|
|
87
90
|
--ui-overlay: rgb(2 6 23 / 0.6);
|
package/dist/tokens.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuD9C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBlD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,MAAM,yBAAQ,CAAC"}
|
package/dist/tokens.js
CHANGED
|
@@ -24,6 +24,7 @@ export const tokenValues = {
|
|
|
24
24
|
"--ui-border": "#e2e8f0", // slate-200
|
|
25
25
|
"--ui-surface": "#ffffff", // white
|
|
26
26
|
"--ui-surface-muted": "#f8fafc", // slate-50
|
|
27
|
+
"--ui-highlight": "#fde68a", // amber-200 — transient "just changed" flash
|
|
27
28
|
"--ui-tooltip": "#0f172a", // slate-900
|
|
28
29
|
"--ui-hover-overlay": "rgb(255 255 255 / 0.32)",
|
|
29
30
|
"--ui-overlay": "rgb(15 23 42 / 0.45)", // slate-900 / 45%
|
|
@@ -77,6 +78,7 @@ export const darkTokenValues = {
|
|
|
77
78
|
"--ui-border": "#334155", // slate-700
|
|
78
79
|
"--ui-surface": "#0f172a", // slate-900
|
|
79
80
|
"--ui-surface-muted": "#1e293b", // slate-800
|
|
81
|
+
"--ui-highlight": "#854d0e", // amber-800 — transient "just changed" flash on dark
|
|
80
82
|
"--ui-tooltip": "#020617", // slate-950
|
|
81
83
|
"--ui-hover-overlay": "rgb(255 255 255 / 0.12)",
|
|
82
84
|
"--ui-overlay": "rgb(2 6 23 / 0.6)", // slate-950 / 60%
|
package/dist/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAA2B;IACjD,SAAS;IACT,cAAc,EAAE,SAAS,EAAE,aAAa;IACxC,oBAAoB,EAAE,SAAS,EAAE,aAAa;IAC9C,WAAW,EAAE,SAAS,EAAE,UAAU;IAClC,iBAAiB,EAAE,SAAS,EAAE,UAAU;IACxC,aAAa,EAAE,SAAS,EAAE,UAAU;IACpC,mBAAmB,EAAE,SAAS,EAAE,UAAU;IAC1C,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,oBAAoB,EAAE,SAAS,EAAE,YAAY;IAC7C,gBAAgB,EAAE,SAAS;IAC3B,WAAW,EAAE,SAAS,EAAE,YAAY;IACpC,iBAAiB,EAAE,SAAS,EAAE,YAAY;IAC1C,aAAa,EAAE,SAAS,EAAE,YAAY;IACtC,cAAc,EAAE,SAAS,EAAE,QAAQ;IACnC,oBAAoB,EAAE,SAAS,EAAE,WAAW;IAC5C,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,oBAAoB,EAAE,yBAAyB;IAC/C,cAAc,EAAE,sBAAsB,EAAE,kBAAkB;IAE1D,gBAAgB;IAChB,aAAa,EAAE,QAAQ,EAAE,aAAa;IACtC,gBAAgB,EAAE,SAAS,EAAE,UAAU;IACvC,aAAa,EACX,kEAAkE,EAAE,YAAY;IAClF,gBAAgB,EACd,qEAAqE,EAAE,YAAY;IACrF,iBAAiB,EAAE,iCAAiC;IAEpD,OAAO;IACP,WAAW,EACT,oHAAoH;IACtH,gBAAgB,EACd,kEAAkE;IACpE,mBAAmB,EAAE,MAAM,EAAE,YAAY;IACzC,gBAAgB,EAAE,UAAU,EAAE,UAAU;IACxC,mBAAmB,EAAE,SAAS,EAAE,UAAU;IAC1C,mBAAmB,EAAE,WAAW;IAEhC,wDAAwD;IACxD,0BAA0B,EAAE,KAAK;IACjC,yBAAyB,EAAE,KAAK;IAChC,2BAA2B,EAAE,KAAK;IAClC,uBAAuB,EAAE,KAAK;IAE9B,2EAA2E;IAC3E,wBAAwB,EAAE,GAAG;IAC7B,wBAAwB,EAAE,MAAM;IAChC,yBAAyB,EAAE,KAAK;IAEhC,mEAAmE;IACnE,sBAAsB,EAAE,GAAG;IAC3B,oBAAoB,EAAE,QAAQ;CAC/B,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,eAAe,GAA2B;IACrD,cAAc,EAAE,SAAS,EAAE,aAAa;IACxC,oBAAoB,EAAE,SAAS,EAAE,aAAa;IAC9C,WAAW,EAAE,SAAS,EAAE,UAAU;IAClC,iBAAiB,EAAE,SAAS,EAAE,UAAU;IACxC,aAAa,EAAE,SAAS,EAAE,UAAU;IACpC,mBAAmB,EAAE,SAAS,EAAE,UAAU;IAC1C,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,oBAAoB,EAAE,SAAS,EAAE,YAAY;IAC7C,gBAAgB,EAAE,SAAS;IAC3B,WAAW,EAAE,SAAS,EAAE,YAAY;IACpC,iBAAiB,EAAE,SAAS,EAAE,YAAY;IAC1C,aAAa,EAAE,SAAS,EAAE,YAAY;IACtC,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,oBAAoB,EAAE,SAAS,EAAE,YAAY;IAC7C,cAAc,EAAE,SAAS,EAAE,YAAY;IACvC,oBAAoB,EAAE,yBAAyB;IAC/C,cAAc,EAAE,mBAAmB,EAAE,kBAAkB;IACvD,iBAAiB,EAAE,kCAAkC;CACtD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA,EAAE,CAAC","sourcesContent":["import { css } from \"lit\";\n\n/**\n * Design token values, sourced from Tailwind v4's default theme palette.\n * Each entry maps a `--ui-*` custom property name to its default value.\n * These are the same values baked in as `var(--ui-*, <fallback>)` fallbacks\n * throughout component styles, so components render correctly with zero\n * external CSS. Consumers may override any of these by setting the custom\n * property on `:root` or an ancestor element (see `tokens.css`).\n */\nexport const tokenValues: Record<string, string> = {\n // Colors\n \"--ui-primary\": \"#4f46e5\", // indigo-600\n \"--ui-primary-hover\": \"#4338ca\", // indigo-700\n \"--ui-info\": \"#0ea5e9\", // sky-500\n \"--ui-info-hover\": \"#0284c7\", // sky-600\n \"--ui-danger\": \"#dc2626\", // red-600\n \"--ui-danger-hover\": \"#b91c1c\", // red-700\n \"--ui-success\": \"#16a34a\", // green-600\n \"--ui-warning\": \"#d97706\", // amber-600\n \"--ui-warning-hover\": \"#b45309\", // amber-700\n \"--ui-on-accent\": \"#ffffff\",\n \"--ui-text\": \"#0f172a\", // slate-900\n \"--ui-text-muted\": \"#64748b\", // slate-500\n \"--ui-border\": \"#e2e8f0\", // slate-200\n \"--ui-surface\": \"#ffffff\", // white\n \"--ui-surface-muted\": \"#f8fafc\", // slate-50\n \"--ui-tooltip\": \"#0f172a\", // slate-900\n \"--ui-hover-overlay\": \"rgb(255 255 255 / 0.32)\",\n \"--ui-overlay\": \"rgb(15 23 42 / 0.45)\", // slate-900 / 45%\n\n // Shape / depth\n \"--ui-radius\": \"0.5rem\", // rounded-lg\n \"--ui-radius-sm\": \"0.25rem\", // rounded\n \"--ui-shadow\":\n \"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)\", // shadow-md\n \"--ui-shadow-lg\":\n \"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)\", // shadow-xl\n \"--ui-focus-ring\": \"0 0 0 3px rgb(79 70 229 / 0.35)\",\n\n // Type\n \"--ui-font\":\n 'ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"',\n \"--ui-font-mono\":\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n \"--ui-font-size-lg\": \"1rem\", // text-base\n \"--ui-font-size\": \"0.875rem\", // text-sm\n \"--ui-font-size-sm\": \"0.75rem\", // text-xs\n \"--ui-font-size-xs\": \"0.6875rem\",\n\n // Font weights — the only four weights the system uses.\n \"--ui-font-weight-regular\": \"400\",\n \"--ui-font-weight-medium\": \"500\",\n \"--ui-font-weight-semibold\": \"600\",\n \"--ui-font-weight-bold\": \"700\",\n\n // Line heights — glyph (icon/marker box), tight (headings), normal (body).\n \"--ui-line-height-glyph\": \"1\",\n \"--ui-line-height-tight\": \"1.25\",\n \"--ui-line-height-normal\": \"1.5\",\n\n // Letter spacing / tracking — default and the single widened step.\n \"--ui-tracking-normal\": \"0\",\n \"--ui-tracking-wide\": \"0.04em\",\n};\n\n/**\n * Dark-mode overrides for the same `--ui-*` custom properties, applied by\n * `tokens.css` via `@media (prefers-color-scheme: dark)` and `[data-theme]`\n * (see generate-tokens-css.mjs). Same Tailwind slate scale as the light\n * palette, inverted, with primary/danger/success lightened one step (500\n * instead of 600) for sufficient contrast against dark surfaces. Shape/type\n * tokens are theme-independent and not repeated here.\n */\nexport const darkTokenValues: Record<string, string> = {\n \"--ui-primary\": \"#6366f1\", // indigo-500\n \"--ui-primary-hover\": \"#818cf8\", // indigo-400\n \"--ui-info\": \"#38bdf8\", // sky-400\n \"--ui-info-hover\": \"#7dd3fc\", // sky-300\n \"--ui-danger\": \"#ef4444\", // red-500\n \"--ui-danger-hover\": \"#f87171\", // red-400\n \"--ui-success\": \"#22c55e\", // green-500\n \"--ui-warning\": \"#f59e0b\", // amber-500\n \"--ui-warning-hover\": \"#fbbf24\", // amber-400\n \"--ui-on-accent\": \"#ffffff\",\n \"--ui-text\": \"#f1f5f9\", // slate-100\n \"--ui-text-muted\": \"#94a3b8\", // slate-400\n \"--ui-border\": \"#334155\", // slate-700\n \"--ui-surface\": \"#0f172a\", // slate-900\n \"--ui-surface-muted\": \"#1e293b\", // slate-800\n \"--ui-tooltip\": \"#020617\", // slate-950\n \"--ui-hover-overlay\": \"rgb(255 255 255 / 0.12)\",\n \"--ui-overlay\": \"rgb(2 6 23 / 0.6)\", // slate-950 / 60%\n \"--ui-focus-ring\": \"0 0 0 3px rgb(99 102 241 / 0.45)\",\n};\n\n/**\n * Historically a shared `:host { --ui-x: var(--ui-x, fallback); } ` block,\n * re-declaring every token on each component's own host element as a\n * \"materialize the inherited value, or this fallback\" trick. That pattern\n * turned out to be a genuine bug, not a working default: browsers treat\n * `--ui-x: var(--ui-x, ...)` on `:host` as a self-referencing declaration\n * that computes to the guaranteed-invalid value REGARDLESS of what an\n * ancestor (e.g. `:root`) set — the host's own `:host` rule wins the cascade\n * over the ancestor's, so this dropped whatever the app actually set and\n * silently substituted the component's own fallback everywhere. It went\n * unnoticed because every component's fallback happened to equal the\n * intended light-mode value — dark mode (a real, different value at\n * `:root`) exposed it immediately (colors rendering as if no theme were\n * applied at all). Fix: don't redeclare tokens on `:host` — plain\n * inheritance already carries `:root`'s values into every shadow root\n * correctly, and every component already has its own `var(--ui-x, fallback)`\n * at each point of use, so nothing here is needed for the \"zero external\n * CSS\" default to keep working. Kept as an empty export so the existing\n * `static override styles = [tokens, css\\`...\\`]` import in every component\n * keeps compiling.\n */\nexport const tokens = css``;\n"]}
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import { css } from \"lit\";\n\n/**\n * Design token values, sourced from Tailwind v4's default theme palette.\n * Each entry maps a `--ui-*` custom property name to its default value.\n * These are the same values baked in as `var(--ui-*, <fallback>)` fallbacks\n * throughout component styles, so components render correctly with zero\n * external CSS. Consumers may override any of these by setting the custom\n * property on `:root` or an ancestor element (see `tokens.css`).\n */\nexport const tokenValues: Record<string, string> = {\n // Colors\n \"--ui-primary\": \"#4f46e5\", // indigo-600\n \"--ui-primary-hover\": \"#4338ca\", // indigo-700\n \"--ui-info\": \"#0ea5e9\", // sky-500\n \"--ui-info-hover\": \"#0284c7\", // sky-600\n \"--ui-danger\": \"#dc2626\", // red-600\n \"--ui-danger-hover\": \"#b91c1c\", // red-700\n \"--ui-success\": \"#16a34a\", // green-600\n \"--ui-warning\": \"#d97706\", // amber-600\n \"--ui-warning-hover\": \"#b45309\", // amber-700\n \"--ui-on-accent\": \"#ffffff\",\n \"--ui-text\": \"#0f172a\", // slate-900\n \"--ui-text-muted\": \"#64748b\", // slate-500\n \"--ui-border\": \"#e2e8f0\", // slate-200\n \"--ui-surface\": \"#ffffff\", // white\n \"--ui-surface-muted\": \"#f8fafc\", // slate-50\n \"--ui-highlight\": \"#fde68a\", // amber-200 — transient \"just changed\" flash\n \"--ui-tooltip\": \"#0f172a\", // slate-900\n \"--ui-hover-overlay\": \"rgb(255 255 255 / 0.32)\",\n \"--ui-overlay\": \"rgb(15 23 42 / 0.45)\", // slate-900 / 45%\n\n // Shape / depth\n \"--ui-radius\": \"0.5rem\", // rounded-lg\n \"--ui-radius-sm\": \"0.25rem\", // rounded\n \"--ui-shadow\":\n \"0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)\", // shadow-md\n \"--ui-shadow-lg\":\n \"0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)\", // shadow-xl\n \"--ui-focus-ring\": \"0 0 0 3px rgb(79 70 229 / 0.35)\",\n\n // Type\n \"--ui-font\":\n 'ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"',\n \"--ui-font-mono\":\n \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n \"--ui-font-size-lg\": \"1rem\", // text-base\n \"--ui-font-size\": \"0.875rem\", // text-sm\n \"--ui-font-size-sm\": \"0.75rem\", // text-xs\n \"--ui-font-size-xs\": \"0.6875rem\",\n\n // Font weights — the only four weights the system uses.\n \"--ui-font-weight-regular\": \"400\",\n \"--ui-font-weight-medium\": \"500\",\n \"--ui-font-weight-semibold\": \"600\",\n \"--ui-font-weight-bold\": \"700\",\n\n // Line heights — glyph (icon/marker box), tight (headings), normal (body).\n \"--ui-line-height-glyph\": \"1\",\n \"--ui-line-height-tight\": \"1.25\",\n \"--ui-line-height-normal\": \"1.5\",\n\n // Letter spacing / tracking — default and the single widened step.\n \"--ui-tracking-normal\": \"0\",\n \"--ui-tracking-wide\": \"0.04em\",\n};\n\n/**\n * Dark-mode overrides for the same `--ui-*` custom properties, applied by\n * `tokens.css` via `@media (prefers-color-scheme: dark)` and `[data-theme]`\n * (see generate-tokens-css.mjs). Same Tailwind slate scale as the light\n * palette, inverted, with primary/danger/success lightened one step (500\n * instead of 600) for sufficient contrast against dark surfaces. Shape/type\n * tokens are theme-independent and not repeated here.\n */\nexport const darkTokenValues: Record<string, string> = {\n \"--ui-primary\": \"#6366f1\", // indigo-500\n \"--ui-primary-hover\": \"#818cf8\", // indigo-400\n \"--ui-info\": \"#38bdf8\", // sky-400\n \"--ui-info-hover\": \"#7dd3fc\", // sky-300\n \"--ui-danger\": \"#ef4444\", // red-500\n \"--ui-danger-hover\": \"#f87171\", // red-400\n \"--ui-success\": \"#22c55e\", // green-500\n \"--ui-warning\": \"#f59e0b\", // amber-500\n \"--ui-warning-hover\": \"#fbbf24\", // amber-400\n \"--ui-on-accent\": \"#ffffff\",\n \"--ui-text\": \"#f1f5f9\", // slate-100\n \"--ui-text-muted\": \"#94a3b8\", // slate-400\n \"--ui-border\": \"#334155\", // slate-700\n \"--ui-surface\": \"#0f172a\", // slate-900\n \"--ui-surface-muted\": \"#1e293b\", // slate-800\n \"--ui-highlight\": \"#854d0e\", // amber-800 — transient \"just changed\" flash on dark\n \"--ui-tooltip\": \"#020617\", // slate-950\n \"--ui-hover-overlay\": \"rgb(255 255 255 / 0.12)\",\n \"--ui-overlay\": \"rgb(2 6 23 / 0.6)\", // slate-950 / 60%\n \"--ui-focus-ring\": \"0 0 0 3px rgb(99 102 241 / 0.45)\",\n};\n\n/**\n * Historically a shared `:host { --ui-x: var(--ui-x, fallback); } ` block,\n * re-declaring every token on each component's own host element as a\n * \"materialize the inherited value, or this fallback\" trick. That pattern\n * turned out to be a genuine bug, not a working default: browsers treat\n * `--ui-x: var(--ui-x, ...)` on `:host` as a self-referencing declaration\n * that computes to the guaranteed-invalid value REGARDLESS of what an\n * ancestor (e.g. `:root`) set — the host's own `:host` rule wins the cascade\n * over the ancestor's, so this dropped whatever the app actually set and\n * silently substituted the component's own fallback everywhere. It went\n * unnoticed because every component's fallback happened to equal the\n * intended light-mode value — dark mode (a real, different value at\n * `:root`) exposed it immediately (colors rendering as if no theme were\n * applied at all). Fix: don't redeclare tokens on `:host` — plain\n * inheritance already carries `:root`'s values into every shadow root\n * correctly, and every component already has its own `var(--ui-x, fallback)`\n * at each point of use, so nothing here is needed for the \"zero external\n * CSS\" default to keep working. Kept as an empty export so the existing\n * `static override styles = [tokens, css\\`...\\`]` import in every component\n * keeps compiling.\n */\nexport const tokens = css``;\n"]}
|
package/docs/design-language.md
CHANGED
|
@@ -86,6 +86,14 @@ literal values are migrated onto them.
|
|
|
86
86
|
- Side panels use a `20rem` compact / `25rem` comfortable width; the shared
|
|
87
87
|
responsive breakpoint is `48rem`.
|
|
88
88
|
- Radio inputs render at `1rem`.
|
|
89
|
+
- Value-entry fields fill their container by default: the host is
|
|
90
|
+
`display: block` and the inner control is `width: 100%`. Shrink-to-fit is
|
|
91
|
+
opt-in per instance via the host (`<tag> { display: inline-block; }` or
|
|
92
|
+
`width: fit-content`). This covers `autocomplete-input`,
|
|
93
|
+
`address-autocomplete`, `editable-text`, `form-select`, and `multi-select`,
|
|
94
|
+
and matches the native/reusable-component convention that a field fills the
|
|
95
|
+
stacked column it lives in while staying overridable from outside the shadow
|
|
96
|
+
DOM.
|
|
89
97
|
- Charts and metadata-only components keep their own domain geometry and are
|
|
90
98
|
exempt from the control-metric grid.
|
|
91
99
|
|
package/docs/form-select.md
CHANGED
|
@@ -7,10 +7,11 @@ a native `<select>` wherever consistent cross-browser styling and a
|
|
|
7
7
|
picker).
|
|
8
8
|
|
|
9
9
|
The trigger fills its host's width (`justify-content: space-between`
|
|
10
|
-
pushes the chevron to the far edge),
|
|
11
|
-
`
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
pushes the chevron to the far edge), and the host is `display: block`, so a
|
|
11
|
+
`form-select` fills its container's width by default — matching the other
|
|
12
|
+
form fields. To make an instance shrink to its content instead (e.g. in a
|
|
13
|
+
filter bar or a status picker), constrain the host:
|
|
14
|
+
`form-select { display: inline-block; }` (or `width: fit-content`).
|
|
14
15
|
|
|
15
16
|
Set `searchable` to replace the button trigger with an editable combobox
|
|
16
17
|
that filters the predefined options by case-insensitive label infix. Typed
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# `<kanban-board>`
|
|
2
|
+
|
|
3
|
+
A configurable kanban board: a horizontally scrolling row of columns, each
|
|
4
|
+
holding cards. **A card's column is its state** — moving a card to another
|
|
5
|
+
column (by drag-and-drop, keyboard, or the detail popover's state selector)
|
|
6
|
+
changes its state, and the board emits a single `card-move` for all three.
|
|
7
|
+
|
|
8
|
+
Data-driven: set the `columns` property to `KanbanColumnData[]`. The board
|
|
9
|
+
keeps its own working copy and mutates it optimistically on every move, so it
|
|
10
|
+
works standalone; re-assign `columns` at any time to stay controlled from a
|
|
11
|
+
store. Cards show only their ticket number and title in the overview; the
|
|
12
|
+
full detail (description, state, created/updated timestamps) opens in a
|
|
13
|
+
screen-centered `popover-panel`.
|
|
14
|
+
|
|
15
|
+
Pointer drag-and-drop supports both cross-column moves and within-column
|
|
16
|
+
reordering with a live drop indicator (set `reorderable` false to keep only
|
|
17
|
+
cross-column moves when intra-column order isn't persisted). Keyboard parity:
|
|
18
|
+
focus a card and press Space to pick it up, arrow keys to move it (left/right
|
|
19
|
+
across columns, up/down within a column), Space to drop, or Escape to cancel;
|
|
20
|
+
Enter opens the detail. Moves are announced in a polite live region, and the
|
|
21
|
+
moved card briefly flashes a warm highlight so you can see where it landed.
|
|
22
|
+
|
|
23
|
+
Set `manual` for a server-authoritative board (API + WebSocket/SSE): every
|
|
24
|
+
move still emits `card-move`, but the board does NOT apply it locally, so it
|
|
25
|
+
reflects only what you assign to `columns` — e.g. the change echoed back over
|
|
26
|
+
the socket. The default is optimistic local updates.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import "@f-ewald/components/kanban-board.js";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<kanban-board label="Project tasks"></kanban-board>
|
|
38
|
+
<script type="module">
|
|
39
|
+
const board = document.querySelector("kanban-board");
|
|
40
|
+
board.columns = [
|
|
41
|
+
{
|
|
42
|
+
id: "todo",
|
|
43
|
+
title: "To Do",
|
|
44
|
+
cards: [
|
|
45
|
+
{
|
|
46
|
+
id: "c1",
|
|
47
|
+
ticket: "PROJ-142",
|
|
48
|
+
title: "Wire up auth callback",
|
|
49
|
+
description: "Handle the OAuth redirect and persist the session token.",
|
|
50
|
+
createdAt: "2026-07-18T09:12:00Z",
|
|
51
|
+
updatedAt: "2026-07-21T14:03:00Z",
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
{ id: "doing", title: "In Progress", cards: [] },
|
|
56
|
+
{ id: "done", title: "Done", cards: [] },
|
|
57
|
+
];
|
|
58
|
+
// A card's column is its state; drag-and-drop, keyboard, and the detail
|
|
59
|
+
// popover state selector all emit the same card-move event.
|
|
60
|
+
board.addEventListener("card-move", (e) => console.log(e.detail));
|
|
61
|
+
board.addEventListener("card-open", (e) => console.log(e.detail.cardId));
|
|
62
|
+
</script>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Attributes / properties
|
|
66
|
+
|
|
67
|
+
| Property | Attribute | Type | Default | Description |
|
|
68
|
+
| --- | --- | --- | --- | --- |
|
|
69
|
+
| `columns` | _(JS property only)_ | `KanbanColumnData[]` | `[]` | Columns (with their cards) to render, in display order. |
|
|
70
|
+
| `label` | `label` | `string` | `"Board"` | Accessible label for the board's group role. |
|
|
71
|
+
| `manual` | `manual` | `boolean` | `false` | Server-authoritative mode. When true, moves emit `card-move` but are not applied to the board locally; it reflects only what you assign to `columns` (e.g. echoed back over WebSocket/SSE), keeping the server as the single source of truth. Defaults to optimistic local updates. |
|
|
72
|
+
| `reorderable` | `reorderable` | `boolean` | `true` | Whether cards can be reordered within a column. Defaults to true. Set false when intra-column order isn't persisted (no server `rank`): drag and keyboard still move cards *between* columns (appended to the target), but reordering inside a column is disabled, so the UI only offers what sticks. |
|
|
73
|
+
|
|
74
|
+
## Events
|
|
75
|
+
|
|
76
|
+
| Event | Description |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `card-move` | A card changed column/position; detail: { cardId, fromColumnId, toColumnId, toIndex }. |
|
|
79
|
+
| `card-open` | A card's detail view was opened; detail: { cardId }. |
|
|
80
|
+
|
|
81
|
+
## Slots
|
|
82
|
+
|
|
83
|
+
_None._
|
|
84
|
+
|
|
85
|
+
## CSS custom properties
|
|
86
|
+
|
|
87
|
+
| Custom property |
|
|
88
|
+
| --- |
|
|
89
|
+
| `--ui-font` |
|
|
90
|
+
| `--ui-font-size` |
|
|
91
|
+
| `--ui-font-size-sm` |
|
|
92
|
+
| `--ui-font-weight-medium` |
|
|
93
|
+
| `--ui-line-height-normal` |
|
|
94
|
+
| `--ui-primary` |
|
|
95
|
+
| `--ui-text` |
|
|
96
|
+
| `--ui-text-muted` |
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# `<kanban-card>`
|
|
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
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
import "@f-ewald/components/kanban-card.js";
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<kanban-card></kanban-card>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Attributes / properties
|
|
25
|
+
|
|
26
|
+
| Property | Attribute | Type | Default | Description |
|
|
27
|
+
| --- | --- | --- | --- | --- |
|
|
28
|
+
| `ticket` | `ticket` | `string` | `""` | Ticket identifier shown before the title, e.g. `"PROJ-142"`. |
|
|
29
|
+
| `heading` | `heading` | `string` | `""` | Card title shown in the overview. |
|
|
30
|
+
|
|
31
|
+
## Events
|
|
32
|
+
|
|
33
|
+
_None._
|
|
34
|
+
|
|
35
|
+
## Slots
|
|
36
|
+
|
|
37
|
+
_None._
|
|
38
|
+
|
|
39
|
+
## CSS custom properties
|
|
40
|
+
|
|
41
|
+
| Custom property |
|
|
42
|
+
| --- |
|
|
43
|
+
| `--ui-border` |
|
|
44
|
+
| `--ui-focus-ring` |
|
|
45
|
+
| `--ui-font` |
|
|
46
|
+
| `--ui-font-size` |
|
|
47
|
+
| `--ui-font-size-sm` |
|
|
48
|
+
| `--ui-font-weight-medium` |
|
|
49
|
+
| `--ui-highlight` |
|
|
50
|
+
| `--ui-line-height-tight` |
|
|
51
|
+
| `--ui-primary` |
|
|
52
|
+
| `--ui-radius` |
|
|
53
|
+
| `--ui-shadow` |
|
|
54
|
+
| `--ui-surface` |
|
|
55
|
+
| `--ui-text` |
|
|
56
|
+
| `--ui-text-muted` |
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# `<kanban-column>`
|
|
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
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import "@f-ewald/components/kanban-column.js";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<kanban-column></kanban-column>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Attributes / properties
|
|
23
|
+
|
|
24
|
+
| Property | Attribute | Type | Default | Description |
|
|
25
|
+
| --- | --- | --- | --- | --- |
|
|
26
|
+
| `heading` | `heading` | `string` | `""` | Column title shown in the header. |
|
|
27
|
+
| `count` | `count` | `number` | `0` | Number of cards in the column, shown as a count badge. |
|
|
28
|
+
| `dragover` | `dragover` | `boolean` | `false` | Set by the board while a card is dragged over this column, for highlight. |
|
|
29
|
+
| `empty` | `empty` | `boolean` | `false` | Whether the column currently has no cards, so it renders an empty hint. |
|
|
30
|
+
|
|
31
|
+
## Events
|
|
32
|
+
|
|
33
|
+
_None._
|
|
34
|
+
|
|
35
|
+
## Slots
|
|
36
|
+
|
|
37
|
+
_None._
|
|
38
|
+
|
|
39
|
+
## CSS custom properties
|
|
40
|
+
|
|
41
|
+
| Custom property |
|
|
42
|
+
| --- |
|
|
43
|
+
| `--ui-border` |
|
|
44
|
+
| `--ui-font` |
|
|
45
|
+
| `--ui-font-size` |
|
|
46
|
+
| `--ui-font-size-sm` |
|
|
47
|
+
| `--ui-font-size-xs` |
|
|
48
|
+
| `--ui-font-weight-medium` |
|
|
49
|
+
| `--ui-font-weight-semibold` |
|
|
50
|
+
| `--ui-line-height-glyph` |
|
|
51
|
+
| `--ui-line-height-tight` |
|
|
52
|
+
| `--ui-primary` |
|
|
53
|
+
| `--ui-radius` |
|
|
54
|
+
| `--ui-radius-sm` |
|
|
55
|
+
| `--ui-surface` |
|
|
56
|
+
| `--ui-surface-muted` |
|
|
57
|
+
| `--ui-text` |
|
|
58
|
+
| `--ui-text-muted` |
|