@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.
- package/README.md +4 -0
- package/custom-elements.json +2329 -301
- 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/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/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
package/llms.txt
CHANGED
|
@@ -399,10 +399,11 @@ a native `<select>` wherever consistent cross-browser styling and a
|
|
|
399
399
|
picker).
|
|
400
400
|
|
|
401
401
|
The trigger fills its host's width (`justify-content: space-between`
|
|
402
|
-
pushes the chevron to the far edge),
|
|
403
|
-
`
|
|
404
|
-
|
|
405
|
-
|
|
402
|
+
pushes the chevron to the far edge), and the host is `display: block`, so a
|
|
403
|
+
`form-select` fills its container's width by default — matching the other
|
|
404
|
+
form fields. To make an instance shrink to its content instead (e.g. in a
|
|
405
|
+
filter bar or a status picker), constrain the host:
|
|
406
|
+
`form-select { display: inline-block; }` (or `width: fit-content`).
|
|
406
407
|
|
|
407
408
|
Set `searchable` to replace the button trigger with an editable combobox
|
|
408
409
|
that filters the predefined options by case-insensitive label infix. Typed
|
|
@@ -522,6 +523,111 @@ Example:
|
|
|
522
523
|
</script>
|
|
523
524
|
```
|
|
524
525
|
|
|
526
|
+
## <kanban-board>
|
|
527
|
+
|
|
528
|
+
A configurable kanban board: a horizontally scrolling row of columns, each
|
|
529
|
+
holding cards. **A card's column is its state** — moving a card to another
|
|
530
|
+
column (by drag-and-drop, keyboard, or the detail popover's state selector)
|
|
531
|
+
changes its state, and the board emits a single `card-move` for all three.
|
|
532
|
+
|
|
533
|
+
Data-driven: set the `columns` property to `KanbanColumnData[]`. The board
|
|
534
|
+
keeps its own working copy and mutates it optimistically on every move, so it
|
|
535
|
+
works standalone; re-assign `columns` at any time to stay controlled from a
|
|
536
|
+
store. Cards show only their ticket number and title in the overview; the
|
|
537
|
+
full detail (description, state, created/updated timestamps) opens in a
|
|
538
|
+
screen-centered `popover-panel`.
|
|
539
|
+
|
|
540
|
+
Pointer drag-and-drop supports both cross-column moves and within-column
|
|
541
|
+
reordering with a live drop indicator (set `reorderable` false to keep only
|
|
542
|
+
cross-column moves when intra-column order isn't persisted). Keyboard parity:
|
|
543
|
+
focus a card and press Space to pick it up, arrow keys to move it (left/right
|
|
544
|
+
across columns, up/down within a column), Space to drop, or Escape to cancel;
|
|
545
|
+
Enter opens the detail. Moves are announced in a polite live region, and the
|
|
546
|
+
moved card briefly flashes a warm highlight so you can see where it landed.
|
|
547
|
+
|
|
548
|
+
Set `manual` for a server-authoritative board (API + WebSocket/SSE): every
|
|
549
|
+
move still emits `card-move`, but the board does NOT apply it locally, so it
|
|
550
|
+
reflects only what you assign to `columns` — e.g. the change echoed back over
|
|
551
|
+
the socket. The default is optimistic local updates.
|
|
552
|
+
|
|
553
|
+
Import: `import "@f-ewald/components/kanban-board.js";`
|
|
554
|
+
|
|
555
|
+
Properties: `columns` (JS property only) : KanbanColumnData[], default []; `label` (attribute `label`) : string, default "Board"; `manual` (attribute `manual`) : boolean, default false; `reorderable` (attribute `reorderable`) : boolean, default true
|
|
556
|
+
Events: `card-move`, `card-open`
|
|
557
|
+
CSS custom properties: `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-line-height-normal`, `--ui-primary`, `--ui-text`, `--ui-text-muted`
|
|
558
|
+
|
|
559
|
+
Example:
|
|
560
|
+
```html
|
|
561
|
+
<kanban-board label="Project tasks"></kanban-board>
|
|
562
|
+
<script type="module">
|
|
563
|
+
const board = document.querySelector("kanban-board");
|
|
564
|
+
board.columns = [
|
|
565
|
+
{
|
|
566
|
+
id: "todo",
|
|
567
|
+
title: "To Do",
|
|
568
|
+
cards: [
|
|
569
|
+
{
|
|
570
|
+
id: "c1",
|
|
571
|
+
ticket: "PROJ-142",
|
|
572
|
+
title: "Wire up auth callback",
|
|
573
|
+
description: "Handle the OAuth redirect and persist the session token.",
|
|
574
|
+
createdAt: "2026-07-18T09:12:00Z",
|
|
575
|
+
updatedAt: "2026-07-21T14:03:00Z",
|
|
576
|
+
},
|
|
577
|
+
],
|
|
578
|
+
},
|
|
579
|
+
{ id: "doing", title: "In Progress", cards: [] },
|
|
580
|
+
{ id: "done", title: "Done", cards: [] },
|
|
581
|
+
];
|
|
582
|
+
// A card's column is its state; drag-and-drop, keyboard, and the detail
|
|
583
|
+
// popover state selector all emit the same card-move event.
|
|
584
|
+
board.addEventListener("card-move", (e) => console.log(e.detail));
|
|
585
|
+
board.addEventListener("card-open", (e) => console.log(e.detail.cardId));
|
|
586
|
+
</script>
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
## <kanban-card>
|
|
590
|
+
|
|
591
|
+
A single kanban card's compact overview: its ticket number and title only.
|
|
592
|
+
Purely presentational and metadata-only — it is created and driven by
|
|
593
|
+
`kanban-board`, which owns drag-and-drop, selection, and the richer detail
|
|
594
|
+
view (description, state, and timestamps live in the board's popover, not
|
|
595
|
+
here). The board sets `draggable`, toggles the `dragging`/`grabbed`
|
|
596
|
+
attributes for pointer and keyboard moves, and binds the open/keyboard
|
|
597
|
+
handlers; focus is delegated to the inner control so the board can move
|
|
598
|
+
keyboard focus to a card after a move.
|
|
599
|
+
|
|
600
|
+
Import: `import "@f-ewald/components/kanban-card.js";`
|
|
601
|
+
|
|
602
|
+
Properties: `ticket` (attribute `ticket`) : string, default ""; `heading` (attribute `heading`) : string, default ""
|
|
603
|
+
Events: none
|
|
604
|
+
CSS custom properties: `--ui-border`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-highlight`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius`, `--ui-shadow`, `--ui-surface`, `--ui-text`, `--ui-text-muted`
|
|
605
|
+
|
|
606
|
+
Example:
|
|
607
|
+
```html
|
|
608
|
+
<kanban-card></kanban-card>
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
## <kanban-column>
|
|
612
|
+
|
|
613
|
+
A single kanban column: a titled, vertically scrollable region that holds
|
|
614
|
+
its `kanban-card` children (its default `<slot>`), with a header showing the
|
|
615
|
+
column title and card count. Purely presentational and metadata-only —
|
|
616
|
+
`kanban-board` creates it, positions the cards inside it, and drives the
|
|
617
|
+
drop-target highlight via the reflected `dragover` attribute and the empty
|
|
618
|
+
hint via `empty`.
|
|
619
|
+
|
|
620
|
+
Import: `import "@f-ewald/components/kanban-column.js";`
|
|
621
|
+
|
|
622
|
+
Properties: `heading` (attribute `heading`) : string, default ""; `count` (attribute `count`) : number, default 0; `dragover` (attribute `dragover`) : boolean, default false; `empty` (attribute `empty`) : boolean, default false
|
|
623
|
+
Events: none
|
|
624
|
+
CSS custom properties: `--ui-border`, `--ui-font`, `--ui-font-size`, `--ui-font-size-sm`, `--ui-font-size-xs`, `--ui-font-weight-medium`, `--ui-font-weight-semibold`, `--ui-line-height-glyph`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius`, `--ui-radius-sm`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
|
|
625
|
+
|
|
626
|
+
Example:
|
|
627
|
+
```html
|
|
628
|
+
<kanban-column></kanban-column>
|
|
629
|
+
```
|
|
630
|
+
|
|
525
631
|
## <kbd-hint>
|
|
526
632
|
|
|
527
633
|
Renders a keyboard shortcut as one boxed keycap per `+`-separated token.
|
|
@@ -602,6 +708,78 @@ Example:
|
|
|
602
708
|
<map-pin color="#22c55e" size="26" highlighted>🏠</map-pin>
|
|
603
709
|
```
|
|
604
710
|
|
|
711
|
+
## <multi-select>
|
|
712
|
+
|
|
713
|
+
A form-associated multi-select: a trigger showing a compact summary of the
|
|
714
|
+
current selection, opening a multi-selectable listbox popover, with an
|
|
715
|
+
optional removable-chip list of the chosen values. A drop-in generic
|
|
716
|
+
replacement for a native `<select multiple>` — set `name` on the element
|
|
717
|
+
itself and each
|
|
718
|
+
selected value is submitted as a repeated `name=value` entry, matching native
|
|
719
|
+
multiple-select semantics; `new FormData(form).getAll(name)` and
|
|
720
|
+
`form.reset()` work unchanged.
|
|
721
|
+
|
|
722
|
+
The trigger visually follows `form-select`: a `2rem` field showing the
|
|
723
|
+
`placeholder` when empty, the single selected label when one value is chosen,
|
|
724
|
+
and `N selected` when several are. Set `show-chips` to additionally render
|
|
725
|
+
the selected values as compact chips below the trigger, each with an
|
|
726
|
+
accessible `32px` remove control; chips are off by default and the region
|
|
727
|
+
reserves no space while nothing is selected. Like `form-select`, the host is
|
|
728
|
+
`display: block` and fills its container by default; constrain the host
|
|
729
|
+
(`multi-select { display: inline-block; }`) to shrink it to its content
|
|
730
|
+
instead.
|
|
731
|
+
|
|
732
|
+
Set `searchable` to replace the button trigger with an editable combobox that
|
|
733
|
+
infix-filters the predefined options by case-insensitive label. Typed text is
|
|
734
|
+
only a query: `values` changes exclusively when options are toggled, and an
|
|
735
|
+
uncommitted query is discarded when the list closes.
|
|
736
|
+
|
|
737
|
+
The `variant` chooses between two presentations, and `searchable` applies to
|
|
738
|
+
both:
|
|
739
|
+
|
|
740
|
+
- `"dropdown"` (default) is the popover form described above: a compact
|
|
741
|
+
trigger (button, or search combobox when `searchable`) that opens a
|
|
742
|
+
multi-selectable listbox on demand, closes on outside click / Escape, and
|
|
743
|
+
shows a chevron.
|
|
744
|
+
- `"list"` renders the options as a persistently visible, bordered surface
|
|
745
|
+
with no popover, no chevron, and no `open` host state; it never registers
|
|
746
|
+
outside-click listeners. Its scroll viewport is sized to roughly
|
|
747
|
+
`visibleRows` `2rem` rows (see `visible-rows`). When not `searchable` the
|
|
748
|
+
`listbox` itself is focusable and drives Arrow/Home/End/Enter/Space keyboard
|
|
749
|
+
navigation via `aria-activedescendant`; when `searchable` a `2rem` search
|
|
750
|
+
field sits above the list and owns navigation, and Escape only clears the
|
|
751
|
+
query instead of hiding the list.
|
|
752
|
+
|
|
753
|
+
Import: `import "@f-ewald/components/multi-select.js";`
|
|
754
|
+
|
|
755
|
+
Properties: `options` (JS property only) : MultiSelectOption[], default []; `values` (JS property only) : string[], default []; `name` (attribute `name`) : string, default ""; `label` (attribute `label`) : string, default ""; `placeholder` (attribute `placeholder`) : string, default "Select options"; `disabled` (attribute `disabled`) : boolean, default false; `required` (attribute `required`) : boolean, default false; `searchable` (attribute `searchable`) : boolean, default false; `max` (attribute `max`) : number, default 0; `variant` (attribute `variant`) : MultiSelectVariant, default "dropdown"; `visibleRows` (attribute `visible-rows`) : number, default 5; `showChips` (attribute `show-chips`) : boolean, default false
|
|
756
|
+
Events: `change`
|
|
757
|
+
CSS custom properties: `--ui-border`, `--ui-danger`, `--ui-focus-ring`, `--ui-font`, `--ui-font-size-sm`, `--ui-font-weight-medium`, `--ui-font-weight-semibold`, `--ui-line-height-tight`, `--ui-primary`, `--ui-radius`, `--ui-radius-sm`, `--ui-shadow`, `--ui-surface`, `--ui-surface-muted`, `--ui-text`, `--ui-text-muted`
|
|
758
|
+
|
|
759
|
+
Example:
|
|
760
|
+
```html
|
|
761
|
+
<multi-select name="colors" label="Colors" searchable></multi-select>
|
|
762
|
+
<multi-select id="colors-list" variant="list" visible-rows="4"></multi-select>
|
|
763
|
+
<script type="module">
|
|
764
|
+
const options = [
|
|
765
|
+
{ value: "red", label: "Red" },
|
|
766
|
+
{ value: "green", label: "Green" },
|
|
767
|
+
{ value: "blue", label: "Blue" },
|
|
768
|
+
{ value: "amber", label: "Amber" },
|
|
769
|
+
{ value: "violet", label: "Violet" },
|
|
770
|
+
];
|
|
771
|
+
const dropdown = document.querySelector("multi-select[name='colors']");
|
|
772
|
+
dropdown.options = options;
|
|
773
|
+
dropdown.values = ["red", "blue"];
|
|
774
|
+
dropdown.searchable = true;
|
|
775
|
+
dropdown.addEventListener("change", (e) => console.log(e.detail.values));
|
|
776
|
+
|
|
777
|
+
const list = document.getElementById("colors-list");
|
|
778
|
+
list.options = options;
|
|
779
|
+
list.values = ["green"];
|
|
780
|
+
</script>
|
|
781
|
+
```
|
|
782
|
+
|
|
605
783
|
## <percent-bar-chart>
|
|
606
784
|
|
|
607
785
|
Horizontal bar chart for labeled percentage rows, using D3's linear scale.
|