@c2n/dashboard 0.0.13 → 0.0.15

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.
@@ -1 +1 @@
1
- {"schemaVersion":"1.0.0","readme":"","modules":[{"kind":"javascript-module","path":"src/dashboard.ts","declarations":[{"kind":"class","description":"Grid of resizable panes. The children are `c2-dash-card` elements, placed by their `col`/`row` attributes; each\none draws drag handles on the edges it shares with a neighbour, and dragging one resizes the whole track, so the\ncards on either side stay aligned. `columns` and `rows` take a track count (`columns=\"3\"` is three equal columns)\nor an explicit track list (`columns=\"320px 1fr\"`); a track is switched to pixels the first time it is dragged, and\nthe `fr` tracks around it give up the space in proportion to their weight, down to the minimums. With a\n`storage-key` the sizes survive a reload.\n\n`layouts` makes the grid responsive without a remount: each entry names a media query and the tracks and card\nplacements to use while it matches, the first match wins, and every entry keeps its own stored sizes under\n`<storage-key>@<media>`.\n\nPlacement is the application's: the grid never re-places cards on its own. A pane removed or hidden at runtime\nleaves its cells empty and its neighbours where they were, and a pane added at runtime lands exactly where its\n`col`/`row` say, on top of whatever is already there if that cell is taken. To close a gap, or to make room, set\nthe cards' `col`/`row`/`col-span`/`row-span` or hand the grid a `layout` record — both are applied in place.\n\nThe grid is the sizing authority: a card never sets its own width. Give the element a height (or place it in a\nflex/grid parent that does) whenever the rows use `fr`, since the row tracks divide the host's height.","name":"Dashboard","cssProperties":[{"type":{"text":"pixel"},"description":"Gutter between the cards. The whole gutter drags: each card's handle is centred on its edge and as thick as the gap (never under `--c2-dash-card__handle--size`).","name":"--c2-dashboard--gap","default":"8px"},{"type":{"text":"padding"},"description":"Inset around the tracks. With a `background` it is what turns the gutters into a visible frame between the panes.","name":"--c2-dashboard--padding","default":"0px"},{"type":{"text":"background"},"name":"--c2-dashboard--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dashboard--border","default":"none"},{"type":{"text":"border-radius"},"name":"--c2-dashboard--border-radius","default":"0px"}],"slots":[{"description":"The `c2-dash-card` panes. Anything else becomes an ordinary grid item, placed by your own CSS.","name":""}],"members":[{"kind":"field","name":"columns","type":{"text":"number | string | string[]"},"default":"2","description":"Column count (`3`) or an explicit track list (`'320px 1fr'`). Each entry must be one simple size.","attribute":"columns"},{"kind":"field","name":"rows","type":{"text":"number | string | string[]"},"default":"1","description":"Row count (`2`) or an explicit track list (`'auto 1fr'`).","attribute":"rows"},{"kind":"field","name":"minColumnWidth","type":{"text":"number"},"default":"50","description":"Floor for every column, in pixels. A card's own `min-width` raises it for the tracks that card covers.","attribute":"min-column-width"},{"kind":"field","name":"minRowHeight","type":{"text":"number"},"default":"50","description":"Floor for every row, in pixels. A card's own `min-height` raises it for the tracks that card covers.","attribute":"min-row-height"},{"kind":"field","name":"storageKey","type":{"text":"string | undefined"},"default":"undefined","description":"`localStorage` key the track sizes are stored under. Without it the grid starts from the authored tracks.","attribute":"storage-key"},{"kind":"field","name":"layout","type":{"text":"Record<string, DashCardPlacement> | undefined"},"default":"undefined","description":"Placement overrides keyed by the cards' `card-id`, for a layout that is chosen at runtime rather than authored\nin the markup. Each entry wins over the card's own `col`/`row`/`col-span`/`row-span`/visibility. This is also\nhow an app re-flows the remaining panes after one was removed: the grid does not do that by itself."},{"kind":"field","name":"layouts","type":{"text":"DashboardResponsiveLayout[] | undefined"},"default":"undefined","description":"Responsive variants, in priority order: the first entry whose `media` matches supplies the tracks and the card\nplacements, and the grid switches as the viewport crosses a breakpoint. Nothing is stored across entries — each\none keeps its own sizes under `<storage-key>@<media>`."},{"kind":"field","name":"columnTracks","type":{"text":"string[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"rowTracks","type":{"text":"string[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"activeLayout","type":{"text":"number"},"privacy":"private","default":"-1","description":"Index into `layouts` of the entry in force, `-1` for the authored grid."},{"kind":"field","name":"cards","privacy":"private","default":"new Set<DashboardCard>()"},{"kind":"field","name":"mediaQueries","type":{"text":"MediaQueryList[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"handleMediaChange","privacy":"private","readonly":true},{"kind":"field","name":"pixelCache","privacy":"private","default":"new Map<'column' | 'row', number[]>()","description":"Used track sizes, valid until the next write to the tracks."},{"kind":"field","name":"columnSizes","type":{"text":"string[]"},"description":"Column tracks as they are laid out right now.","readonly":true},{"kind":"field","name":"rowSizes","type":{"text":"string[]"},"description":"Row tracks as they are laid out right now.","readonly":true},{"kind":"field","name":"columnCount","type":{"text":"number"},"readonly":true},{"kind":"field","name":"rowCount","type":{"text":"number"},"readonly":true},{"kind":"field","name":"activeResponsiveLayout","type":{"text":"DashboardResponsiveLayout | undefined"},"description":"The entry of `layouts` in force, or `undefined` while the authored grid is.","readonly":true},{"kind":"method","name":"reset","description":"Back to the authored tracks of the layout in force, and its stored ones are forgotten."},{"kind":"method","name":"registerCard","parameters":[{"name":"card","type":{"text":"DashboardCard"}}]},{"kind":"method","name":"unregisterCard","parameters":[{"name":"card","type":{"text":"DashboardCard"}}]},{"kind":"method","name":"placementOf","return":{"type":{"text":"DashCardPlacement | undefined"}},"parameters":[{"name":"cardId","type":{"text":"string | undefined"}}]},{"kind":"method","name":"resizeColumn","return":{"type":{"text":"number"}},"parameters":[{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}}]},{"kind":"method","name":"resizeRow","return":{"type":{"text":"number"}},"parameters":[{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}}]},{"kind":"method","name":"commitResize"},{"kind":"method","name":"splitterValue","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}],"description":"Where the splitter after `index` sits, as a percentage of the tracks' total. A focusable `separator` is a\nwindow splitter, and a window splitter has to report a value."},{"kind":"method","name":"trackPixels","privacy":"private","return":{"type":{"text":"number[]"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}}],"description":"Reading a used track size forces layout, and a drag asks for it from every card's handles on every pointer\nmove. The answer cannot change until something writes to the DOM, so it is cached until one of them does."},{"kind":"method","name":"freeSpace","privacy":"private","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"tracks","type":{"text":"number[]"}}],"description":"What is left of the host along `axis` once the tracks, the gutters and the padding have taken their share."},{"kind":"method","name":"emitLayoutChange","privacy":"private"},{"kind":"method","name":"resizeTrack","privacy":"private","return":{"type":{"text":"{ tracks: string[]; applied: number } | undefined"}},"parameters":[{"name":"tracks","type":{"text":"string[]"}},{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}},{"name":"axis","type":{"text":"'column' | 'row'"}}]},{"kind":"method","name":"trackMin","privacy":"private","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}],"description":"The largest minimum any card covering this track asks for, spread over the tracks that card spans."},{"kind":"method","name":"watchMedia","privacy":"private","description":"One `MediaQueryList` per entry of `layouts`, listened to for as long as the element is connected. Whichever\nentry matches first is the one in force; the listeners re-run the choice whenever any of them flips."},{"kind":"method","name":"unwatchMedia","privacy":"private"},{"kind":"method","name":"resolveActiveLayout","privacy":"private","return":{"type":{"text":"number"}}},{"kind":"field","name":"activeStorageKey","type":{"text":"string | undefined"},"privacy":"private","description":"Each entry of `layouts` stores its own sizes: `<storage-key>@<media>`; the authored grid uses the bare key.","readonly":true},{"kind":"method","name":"syncTracks","privacy":"private"},{"kind":"method","name":"readStored","privacy":"private","return":{"type":{"text":"StoredLayout | null"}}},{"kind":"method","name":"persist","privacy":"private"}],"events":[{"name":"layout-change","type":{"text":"CustomEvent<DashboardLayoutChangeDetail>"},"description":"The track sizes changed: a gesture ended, `reset()` was called, or another entry of `layouts` took over. Does not bubble: listen on the element."}],"attributes":[{"name":"columns","type":{"text":"number | string | string[]"},"default":"2","description":"Column count (`3`) or an explicit track list (`'320px 1fr'`). Each entry must be one simple size.","fieldName":"columns"},{"name":"rows","type":{"text":"number | string | string[]"},"default":"1","description":"Row count (`2`) or an explicit track list (`'auto 1fr'`).","fieldName":"rows"},{"name":"min-column-width","type":{"text":"number"},"default":"50","description":"Floor for every column, in pixels. A card's own `min-width` raises it for the tracks that card covers.","fieldName":"minColumnWidth"},{"name":"min-row-height","type":{"text":"number"},"default":"50","description":"Floor for every row, in pixels. A card's own `min-height` raises it for the tracks that card covers.","fieldName":"minRowHeight"},{"name":"storage-key","type":{"text":"string | undefined"},"default":"undefined","description":"`localStorage` key the track sizes are stored under. Without it the grid starts from the authored tracks.","fieldName":"storageKey"}],"superclass":{"name":"LitElement","package":"lit"},"tagName":"c2-dashboard","customElement":true}],"exports":[{"kind":"js","name":"DashCardPlacement","declaration":{"name":"DashCardPlacement","module":"./dashboard-host"}},{"kind":"js","name":"Dashboard","declaration":{"name":"Dashboard","module":"src/dashboard.ts"}},{"kind":"custom-element-definition","name":"c2-dashboard","declaration":{"name":"Dashboard","module":"src/dashboard.ts"}}]},{"kind":"javascript-module","path":"src/dash-card.ts","declarations":[{"kind":"class","description":"One pane of a `c2-dashboard`. It owns its place in the grid (`col`, `row`, `col-span`, `row-span`), the drag\nhandles on the edges it shares with a neighbour, and the optional expand controls; it draws no surface of its\nown, so put a `c2-card` — or any markup — in the default slot.\n\nA handle resizes the whole grid track, never just this card, and it only appears where there is a neighbour to\ntake the space from: the right edge has one when another column follows, the left edge when one precedes. Drag\nit, or focus it and use the arrow keys (10px a step, 1px with Shift).\n\nFilling the `header`, `actions` or `footer` slot turns on that row; with the header and actions both empty the\nexpand controls float over the top-right corner of the pane instead. An expanded card covers its neighbours on\nan opaque `--c2-dash-card__expanded--background` (the theme's surface colour), while the card itself stays\ntransparent at rest.\n\nA card that arrives while the grid is already on screen fades and scales in; one that leaves — through the\ngrid's `layout` record (`visible: false`) or through `dismiss()`, which removes the element once the animation\nhas played — fades out the same way. Cards present at load do not animate, and `prefers-reduced-motion` turns\nboth off.\n\nEvery built-in icon is a slot whose fallback is the default drawing, so a pane can use the host application's own\nicon set without giving up the behaviour.","name":"DashCard","cssProperties":[{"type":{"text":"background"},"name":"--c2-dash-card--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card--border","default":"none"},{"type":{"text":"border-radius"},"name":"--c2-dash-card--border-radius","default":"0px"},{"type":{"text":"box-shadow"},"name":"--c2-dash-card--box-shadow","default":"none"},{"type":{"text":"padding"},"name":"--c2-dash-card--padding","default":"0px"},{"type":{"text":"overflow"},"description":"`hidden` keeps the content inside the track; switch it to `visible` for a pane that has to overflow, such as one holding a menu.","name":"--c2-dash-card--overflow","default":"hidden"},{"type":{"text":"background"},"description":"Fill while the card is expanded over its neighbours, so they do not show through; the card's own `background` stays transparent.","name":"--c2-dash-card__expanded--background","default":"#ffffff"},{"type":{"text":"number"},"name":"--c2-dash-card__expanded--z-index","default":"20"},{"type":{"text":"duration"},"description":"Fade and scale-in of a card added to a grid that is already on screen, or shown again through the layout record. `0ms` disables it.","name":"--c2-dash-card__enter--animation-duration","default":"200ms"},{"type":{"text":"duration"},"description":"Fade-out before a card is hidden by the layout record or removed by `dismiss()`. `0ms` disables it.","name":"--c2-dash-card__leave--animation-duration","default":"160ms"},{"type":{"text":"duration"},"description":"Length of the scale-in the card plays when it expands or collapses. Ignored under `prefers-reduced-motion`.","name":"--c2-dash-card__expanded--animation-duration","default":"200ms"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--min-height","default":"44px"},{"type":{"text":"padding"},"name":"--c2-dash-card__header--padding-block","default":"8px"},{"type":{"text":"padding"},"name":"--c2-dash-card__header--padding-inline","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--gap","default":"12px"},{"type":{"text":"background"},"name":"--c2-dash-card__header--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card__header--border-bottom","default":"none"},{"type":{"text":"color"},"name":"--c2-dash-card__header--color","default":"#18181b"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--font-size","default":"14px"},{"type":{"text":"font-weight"},"name":"--c2-dash-card__header--font-weight","default":"600"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--min-height","default":"36px"},{"type":{"text":"padding"},"name":"--c2-dash-card__footer--padding-block","default":"6px"},{"type":{"text":"padding"},"name":"--c2-dash-card__footer--padding-inline","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--gap","default":"8px"},{"type":{"text":"background"},"name":"--c2-dash-card__footer--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card__footer--border-top","default":"none"},{"type":{"text":"color"},"name":"--c2-dash-card__footer--color","default":"#71717a"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--font-size","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__actions--gap","default":"8px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__controls--gap","default":"2px"},{"type":{"text":"pixel"},"description":"Inset of the floating control group from the top-right corner, used only while the header row is off.","name":"--c2-dash-card__controls--offset","default":"4px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control--size","default":"24px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control--icon-size","default":"16px"},{"type":{"text":"border-radius"},"name":"--c2-dash-card__control--border-radius","default":"6px"},{"type":{"text":"color"},"name":"--c2-dash-card__control--color","default":"#71717a"},{"type":{"text":"background"},"name":"--c2-dash-card__control--background","default":"transparent"},{"type":{"text":"background"},"name":"--c2-dash-card__control__hover--background","default":"#f4f4f5"},{"type":{"text":"color"},"name":"--c2-dash-card__control__hover--color","default":"#18181b"},{"type":{"text":"outline"},"name":"--c2-dash-card__control__focus--outline","default":"2px solid rgba(2, 101, 220, 0.4)"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control__focus--outline-offset","default":"2px"},{"type":{"text":"pixel"},"description":"Smallest thickness of the grab area on an edge. Inside a grid the handle is as thick as the gutter when that is wider, centred on the edge, so the whole gutter drags.","name":"--c2-dash-card__handle--size","default":"6px"},{"type":{"text":"pixel"},"description":"Gap between the handle's visible bar and the ends of the edge.","name":"--c2-dash-card__handle--inset","default":"2px"},{"type":{"text":"background"},"name":"--c2-dash-card__handle--background","default":"transparent"},{"type":{"text":"background"},"name":"--c2-dash-card__handle__hover--background","default":"rgba(2, 101, 220, 0.2)"},{"type":{"text":"background"},"name":"--c2-dash-card__handle__active--background","default":"rgb(2, 101, 220)"},{"type":{"text":"border-radius"},"name":"--c2-dash-card__handle--border-radius","default":"999px"},{"type":{"text":"duration"},"name":"--c2-dash-card__handle--transition-duration","default":"150ms"},{"type":{"text":"outline"},"name":"--c2-dash-card__handle__focus--outline","default":"2px solid rgba(2, 101, 220, 0.4)"}],"cssParts":[{"description":"The header row, or the floating control group when the header and actions slots are empty.","name":"header"},{"description":"The wrapper around the default slot.","name":"body"},{"description":"The footer row.","name":"footer"},{"description":"The group holding the `controls` slot and the built-in expand buttons.","name":"controls"},{"description":"One built-in expand button.","name":"control"},{"description":"Every drag handle. Each also carries the part of its edge.","name":"handle"},{"description":"The handle on the left edge.","name":"handle-left"},{"description":"The handle on the right edge.","name":"handle-right"},{"description":"The handle on the top edge.","name":"handle-top"},{"description":"The handle on the bottom edge.","name":"handle-bottom"}],"slots":[{"description":"Pane content. It fills the pane: the body is a column flex box and every slotted child is a `flex: 1` item with `min-height: 0`, so a chart or an editor follows the row track without a `height: 100%` chain.","name":""},{"description":"Title area of the header row; filling it turns the row on.","name":"header"},{"description":"Your own controls at the end of the header row, before the built-in expand buttons and separated from them by `--c2-dash-card__actions--gap`.","name":"actions"},{"description":"Your own controls inside the built-in group, immediately before the expand buttons — for a button that belongs with them, such as a refresh or a close.","name":"controls"},{"description":"Status bar under the pane content; filling it turns the row on.","name":"footer"},{"description":"Icon of the full-width control while the card is not expanded that way.","name":"expand-width-icon"},{"description":"Icon of the full-width control while it is.","name":"collapse-width-icon"},{"description":"Icon of the full-height control while the card is not expanded that way.","name":"expand-height-icon"},{"description":"Icon of the full-height control while it is.","name":"collapse-height-icon"},{"description":"Icon of the fullscreen control while the card is not expanded.","name":"expand-full-icon"},{"description":"Icon of the fullscreen control while it is.","name":"collapse-full-icon"}],"members":[{"kind":"field","name":"cardId","type":{"text":"string | undefined"},"default":"undefined","description":"Identifier the grid's `layout` record is keyed by.","attribute":"card-id"},{"kind":"field","name":"col","type":{"text":"number"},"default":"1","description":"1-based column the card starts in.","attribute":"col"},{"kind":"field","name":"row","type":{"text":"number"},"default":"1","description":"1-based row the card starts in.","attribute":"row"},{"kind":"field","name":"colSpan","type":{"text":"number"},"default":"1","description":"Number of columns the card occupies.","attribute":"col-span"},{"kind":"field","name":"rowSpan","type":{"text":"number"},"default":"1","description":"Number of rows the card occupies.","attribute":"row-span"},{"kind":"field","name":"minWidth","type":{"text":"number"},"default":"0","description":"Smallest width in pixels the card accepts; it raises the minimum of every column it covers.","attribute":"min-width"},{"kind":"field","name":"minHeight","type":{"text":"number"},"default":"0","description":"Smallest height in pixels the card accepts; it raises the minimum of every row it covers.","attribute":"min-height"},{"kind":"field","name":"resize","type":{"text":"DashCardResize"},"default":"'both'","description":"Which edges carry a drag handle.","attribute":"resize","reflects":true},{"kind":"field","name":"expandWidth","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every column.","attribute":"expand-width"},{"kind":"field","name":"expandHeight","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every row.","attribute":"expand-height"},{"kind":"field","name":"expandFull","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card over the whole grid.","attribute":"expand-full"},{"kind":"field","name":"expanded","type":{"text":"DashCardExpanded"},"default":"'none'","description":"How far the card is currently expanded. Settable, so an app can expand a card from its own control.","attribute":"expanded","reflects":true},{"kind":"field","name":"hasHeader","type":{"text":"boolean"},"privacy":"private","default":"false"},{"kind":"field","name":"hasActions","type":{"text":"boolean"},"privacy":"private","default":"false"},{"kind":"field","name":"hasSlottedControls","type":{"text":"boolean"},"privacy":"private","default":"false"},{"kind":"field","name":"hasFooter","type":{"text":"boolean"},"privacy":"private","default":"false"},{"kind":"field","name":"dashboard","type":{"text":"DashboardHost | undefined"},"privacy":"private","default":"undefined"},{"kind":"field","name":"leaving","type":{"text":"boolean"},"privacy":"private","default":"false","description":"`true` while the leave animation plays: the handles are gone, the placement is kept until it ends."},{"kind":"field","name":"motion","type":{"text":"Animation | undefined"},"privacy":"private","description":"The enter or leave animation in flight — or the finished leave, kept so a return can cancel its fill."},{"kind":"field","name":"enterPending","type":{"text":"boolean"},"privacy":"private","default":"false","description":"Set when the card should animate in after its next render."},{"kind":"field","name":"constraint","type":{"text":"DashCardConstraint | undefined"},"description":"The grid reads this during a drag; a hidden card asks for nothing.","readonly":true},{"kind":"method","name":"hostChanged","description":"Called by the grid when its shape or its layout record changed."},{"kind":"method","name":"syncVisibility","privacy":"private","description":"Applies the layout record's `visible`. Hiding is deferred until the leave animation has played; showing again\ncancels a leave in flight and animates in. Before the first render, and outside a grid, nothing animates."},{"kind":"method","name":"dismiss","return":{"type":{"text":"Promise<void>"}},"description":"Plays the leave animation, then removes the element from the document. Resolves once it is gone. The other\ncards keep their placement — the grid does not close the gap; re-place them (`col`/`row` or the grid's\n`layout`) once the promise resolves if it should."},{"kind":"field","name":"surface","type":{"text":"HTMLElement | null"},"privacy":"private","readonly":true},{"kind":"method","name":"timing","privacy":"private","return":{"type":{"text":"{ duration: number; easing: string }"}},"parameters":[{"name":"target","type":{"text":"HTMLElement"}},{"name":"phase","type":{"text":"'enter' | 'leave'"}}],"description":"Enter and leave timing, read back from the stylesheet so the variables and `prefers-reduced-motion` apply."},{"kind":"method","name":"cancelMotion","privacy":"private"},{"kind":"method","name":"playEnter","privacy":"private"},{"kind":"method","name":"leave","privacy":"private","return":{"type":{"text":"Promise<boolean>"}},"description":"Fades the card out. Resolves `true` once it has finished — the caller then hides or removes the element — and\n`false` when a return cancelled it. The end state is held (`fill: forwards`) until the next enter cancels it,\nso nothing flashes between the last frame and the hide."},{"kind":"method","name":"syncHandleValues","privacy":"private","description":"The splitter values are written straight onto the handles rather than re-rendered: a drag changes them on\nevery pointer move, and nothing else about the card changes with them."},{"kind":"method","name":"attachToDashboard","privacy":"private","parameters":[{"name":"late","default":"true"}],"description":"The grid may upgrade after its cards do — the card element is in the document either way, so find it and wait\nfor the definition rather than for a parent that is already alive."},{"kind":"field","name":"placement","type":{"text":"EffectivePlacement"},"privacy":"private","readonly":true},{"kind":"method","name":"handleSlotChange","privacy":"private","parameters":[{"name":"event","type":{"text":"Event"}}]},{"kind":"method","name":"updateSection","privacy":"private","parameters":[{"name":"slot","type":{"text":"HTMLSlotElement"}}]},{"kind":"method","name":"startDrag","privacy":"private","parameters":[{"name":"event","type":{"text":"PointerEvent"}},{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"handleHandleKeydown","privacy":"private","parameters":[{"name":"event","type":{"text":"KeyboardEvent"}},{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"toggleExpanded","privacy":"private","parameters":[{"name":"axis","type":{"text":"'width' | 'height' | 'full'"}}]},{"kind":"method","name":"renderControl","privacy":"private","parameters":[{"name":"axis","type":{"text":"'width' | 'height' | 'full'"}},{"name":"active","type":{"text":"boolean"}},{"name":"label","type":{"text":"string"}},{"name":"icon","type":{"text":"TemplateResult"}}]},{"kind":"method","name":"renderControls","privacy":"private"},{"kind":"method","name":"renderHandle","privacy":"private","parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"edge","type":{"text":"'left' | 'right' | 'top' | 'bottom'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"renderHandles","privacy":"private"}],"events":[{"name":"expand-change","type":{"text":"CustomEvent<DashCardExpandChangeDetail>"},"description":"The card was expanded or collapsed through one of its own controls. Does not bubble: listen on the element."}],"attributes":[{"name":"card-id","type":{"text":"string | undefined"},"default":"undefined","description":"Identifier the grid's `layout` record is keyed by.","fieldName":"cardId"},{"name":"col","type":{"text":"number"},"default":"1","description":"1-based column the card starts in.","fieldName":"col"},{"name":"row","type":{"text":"number"},"default":"1","description":"1-based row the card starts in.","fieldName":"row"},{"name":"col-span","type":{"text":"number"},"default":"1","description":"Number of columns the card occupies.","fieldName":"colSpan"},{"name":"row-span","type":{"text":"number"},"default":"1","description":"Number of rows the card occupies.","fieldName":"rowSpan"},{"name":"min-width","type":{"text":"number"},"default":"0","description":"Smallest width in pixels the card accepts; it raises the minimum of every column it covers.","fieldName":"minWidth"},{"name":"min-height","type":{"text":"number"},"default":"0","description":"Smallest height in pixels the card accepts; it raises the minimum of every row it covers.","fieldName":"minHeight"},{"name":"resize","type":{"text":"DashCardResize"},"default":"'both'","description":"Which edges carry a drag handle.","fieldName":"resize"},{"name":"expand-width","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every column.","fieldName":"expandWidth"},{"name":"expand-height","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every row.","fieldName":"expandHeight"},{"name":"expand-full","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card over the whole grid.","fieldName":"expandFull"},{"name":"expanded","type":{"text":"DashCardExpanded"},"default":"'none'","description":"How far the card is currently expanded. Settable, so an app can expand a card from its own control.","fieldName":"expanded"}],"superclass":{"name":"LitElement","package":"lit"},"tagName":"c2-dash-card","customElement":true}],"exports":[{"kind":"js","name":"DashCard","declaration":{"name":"DashCard","module":"src/dash-card.ts"}},{"kind":"custom-element-definition","name":"c2-dash-card","declaration":{"name":"DashCard","module":"src/dash-card.ts"}}]}]}
1
+ {"schemaVersion":"1.0.0","readme":"","modules":[{"kind":"javascript-module","path":"src/dashboard.ts","declarations":[{"kind":"class","description":"Grid of resizable panes. The children are `c2-dash-card` elements, placed by their `col`/`row` attributes; each\none draws drag handles on the edges it shares with a neighbour, and dragging one resizes the whole track, so the\ncards on either side stay aligned. `columns` and `rows` take a track count (`columns=\"3\"` is three equal columns)\nor an explicit track list (`columns=\"320px 1fr\"`); a track is switched to pixels the first time it is dragged, and\nthe `fr` tracks around it give up the space in proportion to their weight, down to the minimums. With a\n`storage-key` the sizes survive a reload.\n\n`layouts` makes the grid responsive without a remount: each entry names a media query and the tracks and card\nplacements to use while it matches, the first match wins, and every entry keeps its own stored sizes under\n`<storage-key>@<media>`. Stored payloads are versioned and include stable card order; `serializeLayout` and\n`deserializeLayout` can preserve application metadata such as named sizes without coupling it to the component.\n\nPlacement is the application's: the grid never re-places cards on its own. A pane removed or hidden at runtime\nleaves its cells empty and its neighbours where they were, and a pane added at runtime lands exactly where its\n`col`/`row` say, on top of whatever is already there if that cell is taken. To close a gap, or to make room, set\nthe cards' `col`/`row`/`col-span`/`row-span` or hand the grid a `layout` record — both are applied in place.\n\nThe grid is the sizing authority: a card never sets its own width. Give the element a height (or place it in a\nflex/grid parent that does) whenever the rows use `fr`, since the row tracks divide the host's height.","name":"Dashboard","cssProperties":[{"type":{"text":"pixel"},"description":"Gutter between the cards. The whole gutter drags: each card's handle is centred on its edge and as thick as the gap (never under `--c2-dash-card__handle--size`).","name":"--c2-dashboard--gap","default":"8px"},{"type":{"text":"padding"},"description":"Inset around the tracks. With a `background` it is what turns the gutters into a visible frame between the panes.","name":"--c2-dashboard--padding","default":"0px"},{"type":{"text":"background"},"name":"--c2-dashboard--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dashboard--border","default":"none"},{"type":{"text":"border-radius"},"name":"--c2-dashboard--border-radius","default":"0px"}],"slots":[{"description":"The `c2-dash-card` panes. Anything else becomes an ordinary grid item, placed by your own CSS.","name":""}],"members":[{"kind":"field","name":"columns","type":{"text":"number | string | string[]"},"default":"2","description":"Column count (`3`) or an explicit track list (`'320px 1fr'`). Each entry must be one simple size.","attribute":"columns"},{"kind":"field","name":"rows","type":{"text":"number | string | string[]"},"default":"1","description":"Row count (`2`) or an explicit track list (`'auto 1fr'`).","attribute":"rows"},{"kind":"field","name":"minColumnWidth","type":{"text":"number"},"default":"50","description":"Floor for every column, in pixels. A card's own `min-width` raises it for the tracks that card covers.","attribute":"min-column-width"},{"kind":"field","name":"minRowHeight","type":{"text":"number"},"default":"50","description":"Floor for every row, in pixels. A card's own `min-height` raises it for the tracks that card covers.","attribute":"min-row-height"},{"kind":"field","name":"storageKey","type":{"text":"string | undefined"},"default":"undefined","description":"`localStorage` key the track sizes and stable card order are stored under. Without it the grid starts from the authored layout.","attribute":"storage-key"},{"kind":"field","name":"layout","type":{"text":"Record<string, DashCardPlacement> | undefined"},"default":"undefined","description":"Placement overrides keyed by the cards' `card-id`, for a layout that is chosen at runtime rather than authored\nin the markup. Each entry wins over the card's own `col`/`row`/`col-span`/`row-span`/visibility. This is also\nhow an app re-flows the remaining panes after one was removed: the grid does not do that by itself."},{"kind":"field","name":"layouts","type":{"text":"DashboardResponsiveLayout[] | undefined"},"default":"undefined","description":"Responsive variants, in priority order: the first entry whose `media` matches supplies the tracks and the card\nplacements, and the grid switches as the viewport crosses a breakpoint. Nothing is stored across entries — each\none keeps its own sizes under `<storage-key>@<media>`."},{"kind":"field","name":"serializeLayout","type":{"text":"((layout: DashboardStoredLayout) => unknown) | undefined"},"default":"undefined","description":"Optional storage encoder. Use it to add application metadata such as named panel sizes."},{"kind":"field","name":"deserializeLayout","type":{"text":"((value: unknown) => DashboardStoredLayout | null) | undefined"},"default":"undefined","description":"Optional storage decoder paired with `serializeLayout`. It may also migrate older application payloads."},{"kind":"field","name":"columnTracks","type":{"text":"string[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"rowTracks","type":{"text":"string[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"activeLayout","type":{"text":"number"},"privacy":"private","default":"-1","description":"Index into `layouts` of the entry in force, `-1` for the authored grid."},{"kind":"field","name":"cards","privacy":"private","default":"new Set<DashboardCard>()"},{"kind":"field","name":"mediaQueries","type":{"text":"MediaQueryList[]"},"privacy":"private","default":"[]"},{"kind":"field","name":"handleMediaChange","privacy":"private","readonly":true},{"kind":"field","name":"pixelCache","privacy":"private","default":"new Map<'column' | 'row', number[]>()","description":"Used track sizes, valid until the next write to the tracks."},{"kind":"field","name":"columnSizes","type":{"text":"string[]"},"description":"Column tracks as they are laid out right now.","readonly":true},{"kind":"field","name":"rowSizes","type":{"text":"string[]"},"description":"Row tracks as they are laid out right now.","readonly":true},{"kind":"field","name":"columnCount","type":{"text":"number"},"readonly":true},{"kind":"field","name":"rowCount","type":{"text":"number"},"readonly":true},{"kind":"field","name":"activeResponsiveLayout","type":{"text":"DashboardResponsiveLayout | undefined"},"description":"The entry of `layouts` in force, or `undefined` while the authored grid is.","readonly":true},{"kind":"method","name":"reset","description":"Back to the authored tracks of the layout in force, and its stored ones are forgotten."},{"kind":"method","name":"registerCard","parameters":[{"name":"card","type":{"text":"DashboardCard"}}]},{"kind":"method","name":"unregisterCard","parameters":[{"name":"card","type":{"text":"DashboardCard"}}]},{"kind":"method","name":"placementOf","return":{"type":{"text":"DashCardPlacement | undefined"}},"parameters":[{"name":"cardId","type":{"text":"string | undefined"}}]},{"kind":"method","name":"resizeColumn","return":{"type":{"text":"number"}},"parameters":[{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}}]},{"kind":"method","name":"resizeRow","return":{"type":{"text":"number"}},"parameters":[{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}}]},{"kind":"method","name":"commitResize"},{"kind":"method","name":"setPanelOrder","parameters":[{"name":"order","type":{"text":"readonly string[]"}}],"description":"Reorders known cards by stable `card-id`, persists the order, and reports one layout change."},{"kind":"method","name":"splitterValue","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}],"description":"Where the splitter after `index` sits, as a percentage of the tracks' total. A focusable `separator` is a\nwindow splitter, and a window splitter has to report a value."},{"kind":"method","name":"trackPixels","privacy":"private","return":{"type":{"text":"number[]"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}}],"description":"Reading a used track size forces layout, and a drag asks for it from every card's handles on every pointer\nmove. The answer cannot change until something writes to the DOM, so it is cached until one of them does."},{"kind":"method","name":"freeSpace","privacy":"private","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"tracks","type":{"text":"number[]"}}],"description":"What is left of the host along `axis` once the tracks, the gutters and the padding have taken their share."},{"kind":"method","name":"emitLayoutChange","privacy":"private"},{"kind":"method","name":"resizeTrack","privacy":"private","return":{"type":{"text":"{ tracks: string[]; applied: number } | undefined"}},"parameters":[{"name":"tracks","type":{"text":"string[]"}},{"name":"index","type":{"text":"number"}},{"name":"delta","type":{"text":"number"}},{"name":"axis","type":{"text":"'column' | 'row'"}}]},{"kind":"method","name":"trackMin","privacy":"private","return":{"type":{"text":"number"}},"parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}],"description":"The largest minimum any card covering this track asks for, spread over the tracks that card spans."},{"kind":"method","name":"watchMedia","privacy":"private","description":"One `MediaQueryList` per entry of `layouts`, listened to for as long as the element is connected. Whichever\nentry matches first is the one in force; the listeners re-run the choice whenever any of them flips."},{"kind":"method","name":"unwatchMedia","privacy":"private"},{"kind":"method","name":"resolveActiveLayout","privacy":"private","return":{"type":{"text":"number"}}},{"kind":"field","name":"activeStorageKey","type":{"text":"string | undefined"},"privacy":"private","description":"Each entry of `layouts` stores its own sizes: `<storage-key>@<media>`; the authored grid uses the bare key.","readonly":true},{"kind":"method","name":"syncTracks","privacy":"private"},{"kind":"method","name":"readStored","privacy":"private","return":{"type":{"text":"DashboardStoredLayout | null"}}},{"kind":"method","name":"persist","privacy":"private"},{"kind":"field","name":"panelOrder","type":{"text":"string[]"},"privacy":"private","readonly":true},{"kind":"method","name":"applyPanelOrder","privacy":"private","parameters":[{"name":"order","type":{"text":"readonly string[]"}}]}],"events":[{"name":"layout-change","type":{"text":"CustomEvent<DashboardLayoutChangeDetail>"},"description":"The tracks or stable card order changed: a gesture ended, `setPanelOrder()`/`reset()` was called, or another entry of `layouts` took over. Includes the active breakpoint. Does not bubble: listen on the element."}],"attributes":[{"name":"columns","type":{"text":"number | string | string[]"},"default":"2","description":"Column count (`3`) or an explicit track list (`'320px 1fr'`). Each entry must be one simple size.","fieldName":"columns"},{"name":"rows","type":{"text":"number | string | string[]"},"default":"1","description":"Row count (`2`) or an explicit track list (`'auto 1fr'`).","fieldName":"rows"},{"name":"min-column-width","type":{"text":"number"},"default":"50","description":"Floor for every column, in pixels. A card's own `min-width` raises it for the tracks that card covers.","fieldName":"minColumnWidth"},{"name":"min-row-height","type":{"text":"number"},"default":"50","description":"Floor for every row, in pixels. A card's own `min-height` raises it for the tracks that card covers.","fieldName":"minRowHeight"},{"name":"storage-key","type":{"text":"string | undefined"},"default":"undefined","description":"`localStorage` key the track sizes and stable card order are stored under. Without it the grid starts from the authored layout.","fieldName":"storageKey"}],"superclass":{"name":"LitElement","package":"lit"},"tagName":"c2-dashboard","customElement":true}],"exports":[{"kind":"js","name":"DashCardPlacement","declaration":{"name":"DashCardPlacement","module":"./dashboard-host"}},{"kind":"js","name":"Dashboard","declaration":{"name":"Dashboard","module":"src/dashboard.ts"}},{"kind":"custom-element-definition","name":"c2-dashboard","declaration":{"name":"Dashboard","module":"src/dashboard.ts"}}]},{"kind":"javascript-module","path":"src/dash-card.ts","declarations":[{"kind":"class","description":"One pane of a `c2-dashboard`. It owns its place in the grid (`col`, `row`, `col-span`, `row-span`), the drag\nhandles on the edges it shares with a neighbour, and the optional expand controls; it draws no surface of its\nown, so put a `c2-card` — or any markup — in the default slot.\n\nA handle resizes the whole grid track, never just this card, and it only appears where there is a neighbour to\ntake the space from: the right edge has one when another column follows, the left edge when one precedes. Drag\nit, or focus it and use the arrow keys (10px a step, 1px with Shift).\n\nFilling the `header`, `actions` or `footer` slot turns on that row; with the header and actions both empty the\nexpand controls float over the top-right corner of the pane instead. An expanded card covers its neighbours on\nan opaque `--c2-dash-card__expanded--background` (the theme's surface colour), while the card itself stays\ntransparent at rest.\n\nA card that arrives while the grid is already on screen fades and scales in; one that leaves — through the\ngrid's `layout` record (`visible: false`) or through `dismiss()`, which removes the element once the animation\nhas played — fades out the same way. Cards present at load do not animate, and `prefers-reduced-motion` turns\nboth off.\n\nEvery built-in icon is a slot whose fallback is the default drawing, so a pane can use the host application's own\nicon set without giving up the behaviour.","name":"DashCard","cssProperties":[{"type":{"text":"background"},"name":"--c2-dash-card--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card--border","default":"none"},{"type":{"text":"border-radius"},"name":"--c2-dash-card--border-radius","default":"0px"},{"type":{"text":"box-shadow"},"name":"--c2-dash-card--box-shadow","default":"none"},{"type":{"text":"padding"},"name":"--c2-dash-card--padding","default":"0px"},{"type":{"text":"overflow"},"description":"`hidden` keeps the content inside the track; switch it to `visible` for a pane that has to overflow, such as one holding a menu.","name":"--c2-dash-card--overflow","default":"hidden"},{"type":{"text":"background"},"description":"Fill while the card is expanded over its neighbours, so they do not show through; the card's own `background` stays transparent.","name":"--c2-dash-card__expanded--background","default":"#ffffff"},{"type":{"text":"number"},"name":"--c2-dash-card__expanded--z-index","default":"20"},{"type":{"text":"duration"},"description":"Fade and scale-in of a card added to a grid that is already on screen, or shown again through the layout record. `0ms` disables it.","name":"--c2-dash-card__enter--animation-duration","default":"200ms"},{"type":{"text":"duration"},"description":"Fade-out before a card is hidden by the layout record or removed by `dismiss()`. `0ms` disables it.","name":"--c2-dash-card__leave--animation-duration","default":"160ms"},{"type":{"text":"duration"},"description":"Length of the scale-in the card plays when it expands or collapses. Ignored under `prefers-reduced-motion`.","name":"--c2-dash-card__expanded--animation-duration","default":"200ms"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--min-height","default":"44px"},{"type":{"text":"padding"},"name":"--c2-dash-card__header--padding-block","default":"8px"},{"type":{"text":"padding"},"name":"--c2-dash-card__header--padding-inline","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--gap","default":"12px"},{"type":{"text":"background"},"name":"--c2-dash-card__header--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card__header--border-bottom","default":"none"},{"type":{"text":"color"},"name":"--c2-dash-card__header--color","default":"#18181b"},{"type":{"text":"pixel"},"name":"--c2-dash-card__header--font-size","default":"14px"},{"type":{"text":"font-weight"},"name":"--c2-dash-card__header--font-weight","default":"600"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--min-height","default":"36px"},{"type":{"text":"padding"},"name":"--c2-dash-card__footer--padding-block","default":"6px"},{"type":{"text":"padding"},"name":"--c2-dash-card__footer--padding-inline","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--gap","default":"8px"},{"type":{"text":"background"},"name":"--c2-dash-card__footer--background","default":"transparent"},{"type":{"text":"border"},"name":"--c2-dash-card__footer--border-top","default":"none"},{"type":{"text":"color"},"name":"--c2-dash-card__footer--color","default":"#71717a"},{"type":{"text":"pixel"},"name":"--c2-dash-card__footer--font-size","default":"12px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__actions--gap","default":"8px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__controls--gap","default":"2px"},{"type":{"text":"pixel"},"description":"Inset of the floating control group from the top-right corner, used only while the header row is off.","name":"--c2-dash-card__controls--offset","default":"4px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control--size","default":"24px"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control--icon-size","default":"16px"},{"type":{"text":"border-radius"},"name":"--c2-dash-card__control--border-radius","default":"6px"},{"type":{"text":"color"},"name":"--c2-dash-card__control--color","default":"#71717a"},{"type":{"text":"background"},"name":"--c2-dash-card__control--background","default":"transparent"},{"type":{"text":"background"},"name":"--c2-dash-card__control__hover--background","default":"#f4f4f5"},{"type":{"text":"color"},"name":"--c2-dash-card__control__hover--color","default":"#18181b"},{"type":{"text":"outline"},"name":"--c2-dash-card__control__focus--outline","default":"2px solid rgba(2, 101, 220, 0.4)"},{"type":{"text":"pixel"},"name":"--c2-dash-card__control__focus--outline-offset","default":"2px"},{"type":{"text":"pixel"},"description":"Smallest thickness of the grab area on an edge. Inside a grid the handle is as thick as the gutter when that is wider, centred on the edge, so the whole gutter drags.","name":"--c2-dash-card__handle--size","default":"6px"},{"type":{"text":"pixel"},"description":"Gap between the handle's visible bar and the ends of the edge.","name":"--c2-dash-card__handle--inset","default":"2px"},{"type":{"text":"background"},"name":"--c2-dash-card__handle--background","default":"transparent"},{"type":{"text":"background"},"name":"--c2-dash-card__handle__hover--background","default":"rgba(2, 101, 220, 0.2)"},{"type":{"text":"background"},"name":"--c2-dash-card__handle__active--background","default":"rgb(2, 101, 220)"},{"type":{"text":"border-radius"},"name":"--c2-dash-card__handle--border-radius","default":"999px"},{"type":{"text":"duration"},"name":"--c2-dash-card__handle--transition-duration","default":"150ms"},{"type":{"text":"outline"},"name":"--c2-dash-card__handle__focus--outline","default":"2px solid rgba(2, 101, 220, 0.4)"}],"cssParts":[{"description":"Conditional row containing the `header` and `actions` slots, or the floating controls when both are empty.","name":"header"},{"description":"The wrapper around the default slot.","name":"body"},{"description":"Conditional row wrapping the assigned `footer` slot.","name":"footer"},{"description":"Component-owned group containing the `controls` slot and built-in expand-button fallbacks.","name":"controls"},{"description":"One built-in expand button.","name":"control"},{"description":"Every drag handle. Each also carries the part of its edge.","name":"handle"},{"description":"The handle on the left edge.","name":"handle-left"},{"description":"The handle on the right edge.","name":"handle-right"},{"description":"The handle on the top edge.","name":"handle-top"},{"description":"The handle on the bottom edge.","name":"handle-bottom"}],"slots":[{"description":"Pane content. It fills the pane: the body is a column flex box and every slotted child is a `flex: 1` item with `min-height: 0`, so a chart or an editor follows the row track without a `height: 100%` chain.","name":""},{"description":"Title area of the header row; filling it turns the row on.","name":"header"},{"description":"Your own controls at the end of the header row, before the built-in expand buttons and separated from them by `--c2-dash-card__actions--gap`.","name":"actions"},{"description":"Your own controls inside the built-in group, immediately before the expand buttons — for a button that belongs with them, such as a refresh or a close.","name":"controls"},{"description":"Status bar under the pane content; filling it turns the row on.","name":"footer"},{"description":"Icon of the full-width control while the card is not expanded that way.","name":"expand-width-icon"},{"description":"Icon of the full-width control while it is.","name":"collapse-width-icon"},{"description":"Icon of the full-height control while the card is not expanded that way.","name":"expand-height-icon"},{"description":"Icon of the full-height control while it is.","name":"collapse-height-icon"},{"description":"Icon of the fullscreen control while the card is not expanded.","name":"expand-full-icon"},{"description":"Icon of the fullscreen control while it is.","name":"collapse-full-icon"}],"members":[{"kind":"field","name":"cardId","type":{"text":"string | undefined"},"default":"undefined","description":"Identifier the grid's `layout` record is keyed by.","attribute":"card-id"},{"kind":"field","name":"col","type":{"text":"number"},"default":"1","description":"1-based column the card starts in.","attribute":"col"},{"kind":"field","name":"row","type":{"text":"number"},"default":"1","description":"1-based row the card starts in.","attribute":"row"},{"kind":"field","name":"colSpan","type":{"text":"number"},"default":"1","description":"Number of columns the card occupies.","attribute":"col-span"},{"kind":"field","name":"rowSpan","type":{"text":"number"},"default":"1","description":"Number of rows the card occupies.","attribute":"row-span"},{"kind":"field","name":"minWidth","type":{"text":"number"},"default":"0","description":"Smallest width in pixels the card accepts; it raises the minimum of every column it covers.","attribute":"min-width"},{"kind":"field","name":"minHeight","type":{"text":"number"},"default":"0","description":"Smallest height in pixels the card accepts; it raises the minimum of every row it covers.","attribute":"min-height"},{"kind":"field","name":"resize","type":{"text":"DashCardResize"},"default":"'both'","description":"Which edges carry a drag handle.","attribute":"resize","reflects":true},{"kind":"field","name":"expandWidth","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every column.","attribute":"expand-width"},{"kind":"field","name":"expandHeight","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every row.","attribute":"expand-height"},{"kind":"field","name":"expandFull","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card over the whole grid.","attribute":"expand-full"},{"kind":"field","name":"expanded","type":{"text":"DashCardExpanded"},"default":"'none'","description":"How far the card is currently expanded. Settable, so an app can expand a card from its own control.","attribute":"expanded","reflects":true},{"kind":"field","name":"slotPresence","privacy":"private","readonly":true,"default":"new SlotPresenceController(this, ['header', 'actions', 'controls', 'footer'])"},{"kind":"field","name":"dashboard","type":{"text":"DashboardHost | undefined"},"privacy":"private","default":"undefined"},{"kind":"field","name":"leaving","type":{"text":"boolean"},"privacy":"private","default":"false","description":"`true` while the leave animation plays: the handles are gone, the placement is kept until it ends."},{"kind":"field","name":"motion","type":{"text":"Animation | undefined"},"privacy":"private","description":"The enter or leave animation in flight — or the finished leave, kept so a return can cancel its fill."},{"kind":"field","name":"enterPending","type":{"text":"boolean"},"privacy":"private","default":"false","description":"Set when the card should animate in after its next render."},{"kind":"field","name":"constraint","type":{"text":"DashCardConstraint | undefined"},"description":"The grid reads this during a drag; a hidden card asks for nothing.","readonly":true},{"kind":"method","name":"hostChanged","description":"Called by the grid when its shape or its layout record changed."},{"kind":"method","name":"syncVisibility","privacy":"private","description":"Applies the layout record's `visible`. Hiding is deferred until the leave animation has played; showing again\ncancels a leave in flight and animates in. Before the first render, and outside a grid, nothing animates."},{"kind":"method","name":"dismiss","return":{"type":{"text":"Promise<void>"}},"description":"Plays the leave animation, then removes the element from the document. Resolves once it is gone. The other\ncards keep their placement — the grid does not close the gap; re-place them (`col`/`row` or the grid's\n`layout`) once the promise resolves if it should."},{"kind":"field","name":"surface","type":{"text":"HTMLElement | null"},"privacy":"private","readonly":true},{"kind":"method","name":"timing","privacy":"private","return":{"type":{"text":"{ duration: number; easing: string }"}},"parameters":[{"name":"target","type":{"text":"HTMLElement"}},{"name":"phase","type":{"text":"'enter' | 'leave'"}}],"description":"Enter and leave timing, read back from the stylesheet so the variables and `prefers-reduced-motion` apply."},{"kind":"method","name":"cancelMotion","privacy":"private"},{"kind":"method","name":"playEnter","privacy":"private"},{"kind":"method","name":"leave","privacy":"private","return":{"type":{"text":"Promise<boolean>"}},"description":"Fades the card out. Resolves `true` once it has finished — the caller then hides or removes the element — and\n`false` when a return cancelled it. The end state is held (`fill: forwards`) until the next enter cancels it,\nso nothing flashes between the last frame and the hide."},{"kind":"method","name":"syncHandleValues","privacy":"private","description":"The splitter values are written straight onto the handles rather than re-rendered: a drag changes them on\nevery pointer move, and nothing else about the card changes with them."},{"kind":"method","name":"attachToDashboard","privacy":"private","parameters":[{"name":"late","default":"true"}],"description":"The grid may upgrade after its cards do — the card element is in the document either way, so find it and wait\nfor the definition rather than for a parent that is already alive."},{"kind":"field","name":"placement","type":{"text":"EffectivePlacement"},"privacy":"private","readonly":true},{"kind":"method","name":"handleSlotChange","privacy":"private","parameters":[{"name":"event","type":{"text":"Event"}}]},{"kind":"method","name":"startDrag","privacy":"private","parameters":[{"name":"event","type":{"text":"PointerEvent"}},{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"handleHandleKeydown","privacy":"private","parameters":[{"name":"event","type":{"text":"KeyboardEvent"}},{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"toggleExpanded","privacy":"private","parameters":[{"name":"axis","type":{"text":"'width' | 'height' | 'full'"}}]},{"kind":"method","name":"renderControl","privacy":"private","parameters":[{"name":"axis","type":{"text":"'width' | 'height' | 'full'"}},{"name":"active","type":{"text":"boolean"}},{"name":"label","type":{"text":"string"}},{"name":"icon","type":{"text":"TemplateResult"}}]},{"kind":"method","name":"renderControls","privacy":"private"},{"kind":"method","name":"renderHandle","privacy":"private","parameters":[{"name":"axis","type":{"text":"'column' | 'row'"}},{"name":"edge","type":{"text":"'left' | 'right' | 'top' | 'bottom'"}},{"name":"index","type":{"text":"number"}}]},{"kind":"method","name":"renderHandles","privacy":"private"}],"events":[{"name":"expand-change","type":{"text":"CustomEvent<DashCardExpandChangeDetail>"},"description":"The card was expanded or collapsed through one of its own controls. Does not bubble: listen on the element."}],"attributes":[{"name":"card-id","type":{"text":"string | undefined"},"default":"undefined","description":"Identifier the grid's `layout` record is keyed by.","fieldName":"cardId"},{"name":"col","type":{"text":"number"},"default":"1","description":"1-based column the card starts in.","fieldName":"col"},{"name":"row","type":{"text":"number"},"default":"1","description":"1-based row the card starts in.","fieldName":"row"},{"name":"col-span","type":{"text":"number"},"default":"1","description":"Number of columns the card occupies.","fieldName":"colSpan"},{"name":"row-span","type":{"text":"number"},"default":"1","description":"Number of rows the card occupies.","fieldName":"rowSpan"},{"name":"min-width","type":{"text":"number"},"default":"0","description":"Smallest width in pixels the card accepts; it raises the minimum of every column it covers.","fieldName":"minWidth"},{"name":"min-height","type":{"text":"number"},"default":"0","description":"Smallest height in pixels the card accepts; it raises the minimum of every row it covers.","fieldName":"minHeight"},{"name":"resize","type":{"text":"DashCardResize"},"default":"'both'","description":"Which edges carry a drag handle.","fieldName":"resize"},{"name":"expand-width","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every column.","fieldName":"expandWidth"},{"name":"expand-height","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card across every row.","fieldName":"expandHeight"},{"name":"expand-full","type":{"text":"boolean"},"default":"false","description":"Offers a control that expands the card over the whole grid.","fieldName":"expandFull"},{"name":"expanded","type":{"text":"DashCardExpanded"},"default":"'none'","description":"How far the card is currently expanded. Settable, so an app can expand a card from its own control.","fieldName":"expanded"}],"superclass":{"name":"LitElement","package":"lit"},"tagName":"c2-dash-card","customElement":true}],"exports":[{"kind":"js","name":"DashCard","declaration":{"name":"DashCard","module":"src/dash-card.ts"}},{"kind":"custom-element-definition","name":"c2-dash-card","declaration":{"name":"DashCard","module":"src/dash-card.ts"}}]}]}
@@ -1,10 +1,11 @@
1
1
  import { DASHBOARD_TAG } from "./dashboard-host.js";
2
2
  import { LitElement, html, nothing, svg, unsafeCSS } from "lit";
3
- import { property, state } from "lit/decorators.js";
3
+ import { state } from "lit/decorators.js";
4
+ import { property } from "@c2n/core/lit-helper.js";
4
5
  import { isServer } from "lit-html/is-server.js";
5
6
  import { customElement } from "@c2n/core/element-helper.js";
6
7
  import { classMap } from "lit/directives/class-map.js";
7
- import { hasSlottedContent } from "@c2n/core/dom-helper.js";
8
+ import { SlotPresenceController } from "@c2n/core/dom-helper.js";
8
9
  //#region src/dash-card.scss?inline
9
10
  var dash_card_default = "/* ex : var((width: 24px), width, c2-checkbox) returns var(--c2-checkbox-width, 24px) */\n:host {\n position: relative;\n display: block;\n box-sizing: border-box;\n grid-column: var(--_grid-column, auto);\n grid-row: var(--_grid-row, auto);\n min-width: 0;\n min-height: 0;\n}\n\n:host([hidden]) {\n display: none;\n}\n\n:host([expanded=width]),\n:host([expanded=height]),\n:host([expanded=full]) {\n isolation: isolate;\n z-index: var(--c2-dash-card__expanded--z-index,20);\n background: var(--c2-dash-card__expanded--background,#ffffff);\n animation: c2-dash-card-expand var(--c2-dash-card__expanded--animation-duration,200ms) cubic-bezier(0.25, 0.46, 0.45, 0.94);\n}\n\n@keyframes c2-dash-card-expand {\n from {\n transform: scale(0.97);\n }\n to {\n transform: scale(1);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n :host([expanded=width]),\n :host([expanded=height]),\n :host([expanded=full]) {\n animation: none;\n }\n}\n.c2-dash-card {\n position: relative;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n height: 100%;\n transition-property: none;\n transition-duration: var(--c2-dash-card__enter--animation-duration,200ms), var(--c2-dash-card__leave--animation-duration,160ms);\n transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);\n min-width: 0;\n min-height: 0;\n padding: var(--c2-dash-card--padding,0px);\n overflow: var(--c2-dash-card--overflow,hidden);\n color: inherit;\n background: var(--c2-dash-card--background,transparent);\n border: var(--c2-dash-card--border,none);\n border-radius: var(--c2-dash-card--border-radius,0px);\n box-shadow: var(--c2-dash-card--box-shadow,none);\n}\n\n.c2-dash-card__header {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: space-between;\n box-sizing: border-box;\n gap: var(--c2-dash-card__header--gap,12px);\n min-width: 0;\n min-height: var(--c2-dash-card__header--min-height,44px);\n padding: var(--c2-dash-card__header--padding-block,8px) var(--c2-dash-card__header--padding-inline,12px);\n font-size: var(--c2-dash-card__header--font-size,14px);\n font-weight: var(--c2-dash-card__header--font-weight,600);\n color: var(--c2-dash-card__header--color,#18181b);\n background: var(--c2-dash-card__header--background,transparent);\n border-bottom: var(--c2-dash-card__header--border-bottom,none);\n}\n\n.c2-dash-card:not(.has-header) .c2-dash-card__header {\n position: absolute;\n top: var(--c2-dash-card__controls--offset,4px);\n right: var(--c2-dash-card__controls--offset,4px);\n z-index: 2;\n min-height: 0;\n padding: 0;\n background: none;\n border: none;\n}\n\n.c2-dash-card:not(.has-header) .c2-dash-card__title {\n display: none;\n}\n\n.c2-dash-card__title {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n min-width: 0;\n}\n\n.c2-dash-card__actions {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--c2-dash-card__actions--gap,8px);\n min-width: 0;\n}\n\n.c2-dash-card__controls {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n gap: var(--c2-dash-card__controls--gap,2px);\n}\n\n.c2-dash-card__control {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n box-sizing: border-box;\n width: var(--c2-dash-card__control--size,24px);\n height: var(--c2-dash-card__control--size,24px);\n padding: 0;\n margin: 0;\n color: var(--c2-dash-card__control--color,#71717a);\n cursor: pointer;\n background: var(--c2-dash-card__control--background,transparent);\n border: none;\n border-radius: var(--c2-dash-card__control--border-radius,6px);\n}\n\n.c2-dash-card__control:hover {\n color: var(--c2-dash-card__control__hover--color,#18181b);\n background: var(--c2-dash-card__control__hover--background,#f4f4f5);\n}\n\n.c2-dash-card__control:focus-visible {\n outline: var(--c2-dash-card__control__focus--outline,2px solid rgba(2, 101, 220, 0.4));\n outline-offset: var(--c2-dash-card__control__focus--outline-offset,2px);\n}\n\n.c2-dash-card__control-icon {\n width: var(--c2-dash-card__control--icon-size,16px);\n height: var(--c2-dash-card__control--icon-size,16px);\n}\n\n.c2-dash-card__control ::slotted(*) {\n width: var(--c2-dash-card__control--icon-size,16px);\n height: var(--c2-dash-card__control--icon-size,16px);\n}\n\n.c2-dash-card__body {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n min-width: 0;\n min-height: 0;\n}\n\n.c2-dash-card__body ::slotted(*) {\n flex: 1 1 auto;\n min-width: 0;\n min-height: 0;\n}\n\n.c2-dash-card__footer {\n display: flex;\n flex: 0 0 auto;\n align-items: center;\n box-sizing: border-box;\n gap: var(--c2-dash-card__footer--gap,8px);\n min-width: 0;\n min-height: var(--c2-dash-card__footer--min-height,36px);\n padding: var(--c2-dash-card__footer--padding-block,6px) var(--c2-dash-card__footer--padding-inline,12px);\n font-size: var(--c2-dash-card__footer--font-size,12px);\n color: var(--c2-dash-card__footer--color,#71717a);\n background: var(--c2-dash-card__footer--background,transparent);\n border-top: var(--c2-dash-card__footer--border-top,none);\n}\n\n.c2-dash-card__header[hidden],\n.c2-dash-card__controls[hidden],\n.c2-dash-card__footer[hidden] {\n display: none;\n}\n\n.c2-dash-card__handle {\n position: absolute;\n z-index: 3;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--c2-dash-card__handle--background,transparent);\n touch-action: none;\n}\n\n.c2-dash-card__handle:focus-visible {\n outline: var(--c2-dash-card__handle__focus--outline,2px solid rgba(2, 101, 220, 0.4));\n}\n\n.c2-dash-card__handle-bar {\n display: block;\n background: transparent;\n border-radius: var(--c2-dash-card__handle--border-radius,999px);\n transition: background var(--c2-dash-card__handle--transition-duration,150ms) ease;\n}\n\n.c2-dash-card__handle:hover .c2-dash-card__handle-bar,\n.c2-dash-card__handle:focus-visible .c2-dash-card__handle-bar {\n background: var(--c2-dash-card__handle__hover--background,rgba(2, 101, 220, 0.2));\n}\n\n.c2-dash-card__handle.is-dragging .c2-dash-card__handle-bar {\n background: var(--c2-dash-card__handle__active--background,rgb(2, 101, 220));\n}\n\n.c2-dash-card__handle--left,\n.c2-dash-card__handle--right {\n top: 0;\n width: max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px));\n height: 100%;\n cursor: col-resize;\n}\n.c2-dash-card__handle--left .c2-dash-card__handle-bar,\n.c2-dash-card__handle--right .c2-dash-card__handle-bar {\n width: 2px;\n height: calc(100% - 2 * var(--c2-dash-card__handle--inset,2px));\n}\n\n.c2-dash-card__handle--left {\n left: calc(-0.5 * max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px)));\n}\n\n.c2-dash-card__handle--right {\n right: calc(-0.5 * max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px)));\n}\n\n.c2-dash-card__handle--top,\n.c2-dash-card__handle--bottom {\n left: 0;\n width: 100%;\n height: max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px));\n cursor: row-resize;\n}\n.c2-dash-card__handle--top .c2-dash-card__handle-bar,\n.c2-dash-card__handle--bottom .c2-dash-card__handle-bar {\n width: calc(100% - 2 * var(--c2-dash-card__handle--inset,2px));\n height: 2px;\n}\n\n.c2-dash-card__handle--top {\n top: calc(-0.5 * max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px)));\n}\n\n.c2-dash-card__handle--bottom {\n bottom: calc(-0.5 * max(var(--c2-dash-card__handle--size,6px), var(--_c2-dashboard-gap, 0px)));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .c2-dash-card__handle-bar {\n transition: none;\n }\n .c2-dash-card {\n transition-duration: 0s, 0s;\n }\n}";
10
11
  //#endregion
@@ -62,10 +63,12 @@ var DashCard = class DashCard extends LitElement {
62
63
  this.expandHeight = false;
63
64
  this.expandFull = false;
64
65
  this.expanded = "none";
65
- this.hasHeader = false;
66
- this.hasActions = false;
67
- this.hasSlottedControls = false;
68
- this.hasFooter = false;
66
+ this.slotPresence = new SlotPresenceController(this, [
67
+ "header",
68
+ "actions",
69
+ "controls",
70
+ "footer"
71
+ ]);
69
72
  this.dashboard = void 0;
70
73
  this.leaving = false;
71
74
  this.enterPending = false;
@@ -101,12 +104,6 @@ var DashCard = class DashCard extends LitElement {
101
104
  this.requestUpdate();
102
105
  }
103
106
  willUpdate() {
104
- if (!this.hasUpdated) {
105
- this.hasHeader = hasSlottedContent(this, "header");
106
- this.hasActions = hasSlottedContent(this, "actions");
107
- this.hasSlottedControls = hasSlottedContent(this, "controls");
108
- this.hasFooter = hasSlottedContent(this, "footer");
109
- }
110
107
  this.syncVisibility();
111
108
  }
112
109
  updated() {
@@ -283,22 +280,7 @@ var DashCard = class DashCard extends LitElement {
283
280
  };
284
281
  }
285
282
  handleSlotChange(event) {
286
- this.updateSection(event.target);
287
- }
288
- updateSection(slot) {
289
- const filled = slot.assignedNodes({ flatten: true }).some((node) => node.nodeType === Node.ELEMENT_NODE || (node.textContent ?? "").trim() !== "");
290
- switch (slot.name) {
291
- case "header":
292
- this.hasHeader = filled;
293
- break;
294
- case "actions":
295
- this.hasActions = filled;
296
- break;
297
- case "controls":
298
- this.hasSlottedControls = filled;
299
- break;
300
- case "footer": this.hasFooter = filled;
301
- }
283
+ this.slotPresence.handleSlotChange(event);
302
284
  }
303
285
  startDrag(event, axis, index) {
304
286
  const dashboard = this.dashboard;
@@ -420,8 +402,8 @@ var DashCard = class DashCard extends LitElement {
420
402
  `;
421
403
  }
422
404
  render() {
423
- const hasControls = this.hasSlottedControls || this.expandWidth || this.expandHeight || this.expandFull;
424
- const hasHeaderRow = this.hasHeader || this.hasActions;
405
+ const hasControls = this.slotPresence.has("controls") || this.expandWidth || this.expandHeight || this.expandFull;
406
+ const hasHeaderRow = this.slotPresence.has("header") || this.slotPresence.has("actions");
425
407
  return html`
426
408
  <div class=${classMap({
427
409
  "c2-dash-card": true,
@@ -435,7 +417,7 @@ var DashCard = class DashCard extends LitElement {
435
417
  </div>
436
418
  </div>
437
419
  <div class="c2-dash-card__body" part="body"><slot></slot></div>
438
- <div class="c2-dash-card__footer" part="footer" ?hidden=${!this.hasFooter}>
420
+ <div class="c2-dash-card__footer" part="footer" ?hidden=${!this.slotPresence.has("footer")}>
439
421
  <slot name="footer" @slotchange=${this.handleSlotChange}></slot>
440
422
  </div>
441
423
  </div>
@@ -476,10 +458,6 @@ __decorate([property({
476
458
  attribute: "expand-full"
477
459
  })], DashCard.prototype, "expandFull", void 0);
478
460
  __decorate([property({ reflect: true })], DashCard.prototype, "expanded", void 0);
479
- __decorate([state()], DashCard.prototype, "hasHeader", void 0);
480
- __decorate([state()], DashCard.prototype, "hasActions", void 0);
481
- __decorate([state()], DashCard.prototype, "hasSlottedControls", void 0);
482
- __decorate([state()], DashCard.prototype, "hasFooter", void 0);
483
461
  __decorate([state()], DashCard.prototype, "dashboard", void 0);
484
462
  __decorate([state()], DashCard.prototype, "leaving", void 0);
485
463
  DashCard = __decorate([customElement("c2-dash-card")], DashCard);
package/dist/dash-card.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as DashCard } from "./dash-card-DNRGm1hM.js";
1
+ import { t as DashCard } from "./dash-card-DW6K2ecV.js";
2
2
  export { DashCard };
package/dist/dashboard.js CHANGED
@@ -1,6 +1,7 @@
1
- import { n as __decorate } from "./dash-card-DNRGm1hM.js";
1
+ import { n as __decorate } from "./dash-card-DW6K2ecV.js";
2
2
  import { LitElement, html, unsafeCSS } from "lit";
3
- import { property, state } from "lit/decorators.js";
3
+ import { state } from "lit/decorators.js";
4
+ import { property } from "@c2n/core/lit-helper.js";
4
5
  import { isServer } from "lit-html/is-server.js";
5
6
  import { customElement } from "@c2n/core/element-helper.js";
6
7
  //#region src/dashboard.scss?inline
@@ -39,6 +40,8 @@ var Dashboard = class Dashboard extends LitElement {
39
40
  this.storageKey = void 0;
40
41
  this.layout = void 0;
41
42
  this.layouts = void 0;
43
+ this.serializeLayout = void 0;
44
+ this.deserializeLayout = void 0;
42
45
  this.columnTracks = [];
43
46
  this.rowTracks = [];
44
47
  this.activeLayout = -1;
@@ -133,6 +136,12 @@ var Dashboard = class Dashboard extends LitElement {
133
136
  this.persist();
134
137
  this.emitLayoutChange();
135
138
  }
139
+ /** Reorders known cards by stable `card-id`, persists the order, and reports one layout change. */
140
+ setPanelOrder(order) {
141
+ this.applyPanelOrder(order);
142
+ this.persist();
143
+ this.emitLayoutChange();
144
+ }
136
145
  /**
137
146
  * Where the splitter after `index` sits, as a percentage of the tracks' total. A focusable `separator` is a
138
147
  * window splitter, and a window splitter has to report a value.
@@ -169,7 +178,9 @@ var Dashboard = class Dashboard extends LitElement {
169
178
  this.dispatchEvent(new CustomEvent("layout-change", {
170
179
  detail: {
171
180
  columns: [...this.columnTracks],
172
- rows: [...this.rowTracks]
181
+ rows: [...this.rowTracks],
182
+ order: this.panelOrder,
183
+ breakpoint: this.activeResponsiveLayout?.media ?? null
173
184
  },
174
185
  bubbles: false,
175
186
  composed: true
@@ -255,6 +266,7 @@ var Dashboard = class Dashboard extends LitElement {
255
266
  const stored = this.readStored();
256
267
  this.columnTracks = stored?.columns?.length === columns.length ? [...stored.columns] : columns;
257
268
  this.rowTracks = stored?.rows?.length === rows.length ? [...stored.rows] : rows;
269
+ if (stored?.order?.length) queueMicrotask(() => this.applyPanelOrder(stored.order));
258
270
  }
259
271
  readStored() {
260
272
  const key = this.activeStorageKey;
@@ -263,6 +275,7 @@ var Dashboard = class Dashboard extends LitElement {
263
275
  const raw = localStorage.getItem(key);
264
276
  if (!raw) return null;
265
277
  const parsed = JSON.parse(raw);
278
+ if (this.deserializeLayout) return this.deserializeLayout(parsed);
266
279
  return parsed && typeof parsed === "object" ? parsed : null;
267
280
  } catch {
268
281
  return null;
@@ -272,15 +285,30 @@ var Dashboard = class Dashboard extends LitElement {
272
285
  const key = this.activeStorageKey;
273
286
  if (!key || isServer) return;
274
287
  try {
275
- localStorage.setItem(key, JSON.stringify({
276
- columns: this.columnTracks,
277
- rows: this.rowTracks
278
- }));
288
+ const layout = {
289
+ version: 1,
290
+ columns: [...this.columnTracks],
291
+ rows: [...this.rowTracks],
292
+ order: this.panelOrder,
293
+ breakpoint: this.activeResponsiveLayout?.media ?? null
294
+ };
295
+ localStorage.setItem(key, JSON.stringify(this.serializeLayout ? this.serializeLayout(layout) : layout));
279
296
  } catch {}
280
297
  }
281
298
  render() {
282
299
  return html`<slot></slot>`;
283
300
  }
301
+ get panelOrder() {
302
+ return [...this.children].filter((child) => child instanceof HTMLElement && child.tagName.toLowerCase() === "c2-dash-card").map((card) => card.cardId ?? card.getAttribute("card-id") ?? "").filter(Boolean);
303
+ }
304
+ applyPanelOrder(order) {
305
+ const cards = [...this.children].filter((child) => child instanceof HTMLElement && child.tagName.toLowerCase() === "c2-dash-card");
306
+ const byId = new Map(cards.map((card) => [card.cardId ?? card.getAttribute("card-id") ?? "", card]));
307
+ const ordered = order.map((id) => byId.get(id)).filter((card) => Boolean(card));
308
+ for (const card of cards) if (!ordered.includes(card)) ordered.push(card);
309
+ if (ordered.every((card, index) => card === cards[index])) return;
310
+ this.append(...ordered);
311
+ }
284
312
  };
285
313
  __decorate([property()], Dashboard.prototype, "columns", void 0);
286
314
  __decorate([property()], Dashboard.prototype, "rows", void 0);
@@ -295,6 +323,8 @@ __decorate([property({
295
323
  __decorate([property({ attribute: "storage-key" })], Dashboard.prototype, "storageKey", void 0);
296
324
  __decorate([property({ attribute: false })], Dashboard.prototype, "layout", void 0);
297
325
  __decorate([property({ attribute: false })], Dashboard.prototype, "layouts", void 0);
326
+ __decorate([property({ attribute: false })], Dashboard.prototype, "serializeLayout", void 0);
327
+ __decorate([property({ attribute: false })], Dashboard.prototype, "deserializeLayout", void 0);
298
328
  __decorate([state()], Dashboard.prototype, "columnTracks", void 0);
299
329
  __decorate([state()], Dashboard.prototype, "rowTracks", void 0);
300
330
  __decorate([state()], Dashboard.prototype, "activeLayout", void 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c2n/dashboard",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "type": "module",
5
5
  "main": "dist/dashboard.js",
6
6
  "exports": {
@@ -74,12 +74,12 @@
74
74
  }
75
75
  },
76
76
  "dependencies": {
77
- "@c2n/core": "0.0.13",
77
+ "@c2n/core": "0.0.15",
78
78
  "lit": "3.3.3"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@c2n/config": "*"
82
82
  },
83
83
  "customElements": "custom-elements.json",
84
- "gitHead": "aa19b641f64fbc54c36b7649a8171d7a686abbdd"
84
+ "gitHead": "129a6e537c68c04ed2a36508789bf42c9781e196"
85
85
  }
package/react.d.ts CHANGED
@@ -9,7 +9,8 @@
9
9
  //
10
10
  // On a server-rendered page (Next.js, React Router SSR) write a camelCase property by its kebab-case attribute
11
11
  // name ('row-key', not rowKey): the server emits props verbatim, HTML lowercases them, and hydration does not
12
- // set properties. Those names are listed next to the properties below.
12
+ // set properties. Those names are listed next to the properties below. Structured converter-backed values
13
+ // also accept their serialized string form, so server JSX can emit the same JSON/CSV attribute used by HTML.
13
14
 
14
15
  import type { DetailedHTMLProps, HTMLAttributes } from 'react'
15
16
  import type { DashCard } from '@c2n/dashboard/dash-card.js'
@@ -33,10 +34,12 @@ declare module 'react' {
33
34
  'expand-height'?: Attribute
34
35
  'expand-full'?: Attribute
35
36
  }
36
- 'c2-dashboard': C2Props<Dashboard> & {
37
+ 'c2-dashboard': Omit<C2Props<Dashboard>, 'columns' | 'rows'> & {
37
38
  'min-column-width'?: Attribute
38
39
  'min-row-height'?: Attribute
39
40
  'storage-key'?: Attribute
41
+ columns?: Dashboard['columns'] | string
42
+ rows?: Dashboard['rows'] | string
40
43
  }
41
44
  }
42
45
  }
@@ -60,10 +60,10 @@ export interface DashCard {
60
60
  * @event {CustomEvent<DashCardExpandChangeDetail>} expand-change - The card was expanded or collapsed through one
61
61
  * of its own controls. Does not bubble: listen on the element.
62
62
  *
63
- * @csspart header - The header row, or the floating control group when the header and actions slots are empty.
63
+ * @csspart header - Conditional row containing the `header` and `actions` slots, or the floating controls when both are empty.
64
64
  * @csspart body - The wrapper around the default slot.
65
- * @csspart footer - The footer row.
66
- * @csspart controls - The group holding the `controls` slot and the built-in expand buttons.
65
+ * @csspart footer - Conditional row wrapping the assigned `footer` slot.
66
+ * @csspart controls - Component-owned group containing the `controls` slot and built-in expand-button fallbacks.
67
67
  * @csspart control - One built-in expand button.
68
68
  * @csspart handle - Every drag handle. Each also carries the part of its edge.
69
69
  * @csspart handle-left - The handle on the left edge.
@@ -160,10 +160,7 @@ export declare class DashCard extends LitElement {
160
160
  expandFull: boolean;
161
161
  /** How far the card is currently expanded. Settable, so an app can expand a card from its own control. */
162
162
  expanded: DashCardExpanded;
163
- private hasHeader;
164
- private hasActions;
165
- private hasSlottedControls;
166
- private hasFooter;
163
+ private readonly slotPresence;
167
164
  private dashboard;
168
165
  /** `true` while the leave animation plays: the handles are gone, the placement is kept until it ends. */
169
166
  private leaving;
@@ -213,7 +210,6 @@ export declare class DashCard extends LitElement {
213
210
  private attachToDashboard;
214
211
  private get placement();
215
212
  private handleSlotChange;
216
- private updateSection;
217
213
  private startDrag;
218
214
  private handleHandleKeydown;
219
215
  private toggleExpanded;
@@ -1 +1 @@
1
- {"version":3,"file":"dash-card.d.ts","sourceRoot":"","sources":["../../src/dash-card.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dash-card.d.ts","sourceRoot":"","sources":["../../src/dash-card.ts"],"names":[],"mappings":"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"}
@@ -44,6 +44,8 @@ export interface DashboardHost extends HTMLElement {
44
44
  }
45
45
  /** The part of `c2-dash-card` the grid reads back. */
46
46
  export interface DashboardCard extends HTMLElement {
47
+ /** Stable persistence identity supplied by the card's `card-id`. */
48
+ readonly cardId?: string;
47
49
  /** `undefined` while the card is hidden, so a hidden card constrains nothing. */
48
50
  readonly constraint: DashCardConstraint | undefined;
49
51
  /** The grid changed shape: re-render the placement and the handles. */
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-host.d.ts","sourceRoot":"","sources":["../../src/dashboard-host.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oGAAoG;AACpG,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sGAAsG;IACtG,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,iGAAiG;AACjG,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,kDAAkD;AAClD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8GAA8G;IAC9G,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;IACvC,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;IACzC,mHAAmH;IACnH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAClD,gHAAgH;IAChH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC/C,iEAAiE;IACjE,YAAY,IAAI,IAAI,CAAA;IACpB,kHAAkH;IAClH,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAAA;CACvE;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAA;IACnD,uEAAuE;IACvE,WAAW,IAAI,IAAI,CAAA;CACpB;AAED,eAAO,MAAM,aAAa,iBAAiB,CAAA"}
1
+ {"version":3,"file":"dashboard-host.d.ts","sourceRoot":"","sources":["../../src/dashboard-host.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,oGAAoG;AACpG,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sGAAsG;IACtG,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,iGAAiG;AACjG,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,kDAAkD;AAClD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8GAA8G;IAC9G,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;IACvC,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAAA;IACzC,mHAAmH;IACnH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAClD,gHAAgH;IAChH,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC/C,iEAAiE;IACjE,YAAY,IAAI,IAAI,CAAA;IACpB,kHAAkH;IAClH,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,iBAAiB,GAAG,SAAS,CAAA;CACvE;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,oEAAoE;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAA;IACnD,uEAAuE;IACvE,WAAW,IAAI,IAAI,CAAA;CACpB;AAED,eAAO,MAAM,aAAa,iBAAiB,CAAA"}
@@ -9,6 +9,10 @@ export interface DashboardLayoutChangeDetail {
9
9
  columns: string[];
10
10
  /** Row tracks. */
11
11
  rows: string[];
12
+ /** Stable card IDs in DOM and reading order. */
13
+ order: string[];
14
+ /** Active responsive media query, or `null` for the authored layout. */
15
+ breakpoint: string | null;
12
16
  }
13
17
  /** Events fired by {@link Dashboard}, keyed for `addEventListener`. */
14
18
  export interface DashboardEventMap {
@@ -32,6 +36,13 @@ export interface DashboardResponsiveLayout {
32
36
  /** Placement overrides by `card-id`, merged per card over the grid's `layout`. */
33
37
  layout?: Record<string, DashCardPlacement>;
34
38
  }
39
+ export interface DashboardStoredLayout {
40
+ version?: 1;
41
+ columns?: string[];
42
+ rows?: string[];
43
+ order?: string[];
44
+ breakpoint?: string | null;
45
+ }
35
46
  /**
36
47
  * Grid of resizable panes. The children are `c2-dash-card` elements, placed by their `col`/`row` attributes; each
37
48
  * one draws drag handles on the edges it shares with a neighbour, and dragging one resizes the whole track, so the
@@ -42,7 +53,8 @@ export interface DashboardResponsiveLayout {
42
53
  *
43
54
  * `layouts` makes the grid responsive without a remount: each entry names a media query and the tracks and card
44
55
  * placements to use while it matches, the first match wins, and every entry keeps its own stored sizes under
45
- * `<storage-key>@<media>`.
56
+ * `<storage-key>@<media>`. Stored payloads are versioned and include stable card order; `serializeLayout` and
57
+ * `deserializeLayout` can preserve application metadata such as named sizes without coupling it to the component.
46
58
  *
47
59
  * Placement is the application's: the grid never re-places cards on its own. A pane removed or hidden at runtime
48
60
  * leaves its cells empty and its neighbours where they were, and a pane added at runtime lands exactly where its
@@ -56,8 +68,9 @@ export interface DashboardResponsiveLayout {
56
68
  *
57
69
  * @slot - The `c2-dash-card` panes. Anything else becomes an ordinary grid item, placed by your own CSS.
58
70
  *
59
- * @event {CustomEvent<DashboardLayoutChangeDetail>} layout-change - The track sizes changed: a gesture ended, `reset()`
60
- * was called, or another entry of `layouts` took over. Does not bubble: listen on the element.
71
+ * @event {CustomEvent<DashboardLayoutChangeDetail>} layout-change - The tracks or stable card order changed: a
72
+ * gesture ended, `setPanelOrder()`/`reset()` was called, or another entry of `layouts` took over. Includes the active
73
+ * breakpoint. Does not bubble: listen on the element.
61
74
  *
62
75
  * @cssproperty {pixel} [--c2-dashboard--gap=8px] - Gutter between the cards. The whole gutter drags: each card's
63
76
  * handle is centred on its edge and as thick as the gap (never under `--c2-dash-card__handle--size`).
@@ -77,7 +90,7 @@ export declare class Dashboard extends LitElement {
77
90
  minColumnWidth: number;
78
91
  /** Floor for every row, in pixels. A card's own `min-height` raises it for the tracks that card covers. */
79
92
  minRowHeight: number;
80
- /** `localStorage` key the track sizes are stored under. Without it the grid starts from the authored tracks. */
93
+ /** `localStorage` key the track sizes and stable card order are stored under. Without it the grid starts from the authored layout. */
81
94
  storageKey: string | undefined;
82
95
  /**
83
96
  * Placement overrides keyed by the cards' `card-id`, for a layout that is chosen at runtime rather than authored
@@ -91,6 +104,10 @@ export declare class Dashboard extends LitElement {
91
104
  * one keeps its own sizes under `<storage-key>@<media>`.
92
105
  */
93
106
  layouts: DashboardResponsiveLayout[] | undefined;
107
+ /** Optional storage encoder. Use it to add application metadata such as named panel sizes. */
108
+ serializeLayout: ((layout: DashboardStoredLayout) => unknown) | undefined;
109
+ /** Optional storage decoder paired with `serializeLayout`. It may also migrate older application payloads. */
110
+ deserializeLayout: ((value: unknown) => DashboardStoredLayout | null) | undefined;
94
111
  private columnTracks;
95
112
  private rowTracks;
96
113
  /** Index into `layouts` of the entry in force, `-1` for the authored grid. */
@@ -120,6 +137,8 @@ export declare class Dashboard extends LitElement {
120
137
  resizeColumn(index: number, delta: number): number;
121
138
  resizeRow(index: number, delta: number): number;
122
139
  commitResize(): void;
140
+ /** Reorders known cards by stable `card-id`, persists the order, and reports one layout change. */
141
+ setPanelOrder(order: readonly string[]): void;
123
142
  /**
124
143
  * Where the splitter after `index` sits, as a percentage of the tracks' total. A focusable `separator` is a
125
144
  * window splitter, and a window splitter has to report a value.
@@ -149,6 +168,8 @@ export declare class Dashboard extends LitElement {
149
168
  private readStored;
150
169
  private persist;
151
170
  render(): import("lit-html").TemplateResult<1>;
171
+ private get panelOrder();
172
+ private applyPanelOrder;
152
173
  }
153
174
  declare global {
154
175
  interface HTMLElementTagNameMap {
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/dashboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/dashboard.ts"],"names":[],"mappings":"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"}