@c2n/dashboard 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"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"}}]}]}
@@ -4,8 +4,9 @@ import { property, state } from "lit/decorators.js";
4
4
  import { isServer } from "lit-html/is-server.js";
5
5
  import { customElement } from "@c2n/core/element-helper.js";
6
6
  import { classMap } from "lit/directives/class-map.js";
7
+ import { hasSlottedContent } from "@c2n/core/dom-helper.js";
7
8
  //#region src/dash-card.scss?inline
8
- 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,var(--c2-dash-card--background,transparent));\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 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 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__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: var(--c2-dash-card__handle--size,6px);\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(-1 * var(--c2-dash-card__handle--size,6px) / 2);\n}\n\n.c2-dash-card__handle--right {\n right: calc(-1 * var(--c2-dash-card__handle--size,6px) / 2);\n}\n\n.c2-dash-card__handle--top,\n.c2-dash-card__handle--bottom {\n left: 0;\n width: 100%;\n height: var(--c2-dash-card__handle--size,6px);\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(-1 * var(--c2-dash-card__handle--size,6px) / 2);\n}\n\n.c2-dash-card__handle--bottom {\n bottom: calc(-1 * var(--c2-dash-card__handle--size,6px) / 2);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .c2-dash-card__handle-bar {\n transition: none;\n }\n}";
9
+ 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}";
9
10
  //#endregion
10
11
  //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
11
12
  function __decorate(decorators, target, key, desc) {
@@ -29,6 +30,23 @@ var ICONS = {
29
30
  function clamp(value, min, max) {
30
31
  return Math.min(Math.max(value, min), max);
31
32
  }
33
+ /** First entry of a comma-separated CSS list, leaving the commas inside `cubic-bezier(…)` alone. */
34
+ function firstListEntry(value) {
35
+ let depth = 0;
36
+ for (let i = 0; i < value.length; i++) {
37
+ const char = value[i];
38
+ if (char === "(") depth++;
39
+ else if (char === ")") depth--;
40
+ else if (char === "," && depth === 0) return value.slice(0, i).trim();
41
+ }
42
+ return value.trim();
43
+ }
44
+ /** `'200ms'` → 200, `'0.2s'` → 200. */
45
+ function parseDuration(value) {
46
+ const amount = parseFloat(value);
47
+ if (Number.isNaN(amount)) return 0;
48
+ return value.endsWith("ms") ? amount : amount * 1e3;
49
+ }
32
50
  var DashCard = class DashCard extends LitElement {
33
51
  constructor(..._args) {
34
52
  super(..._args);
@@ -49,6 +67,8 @@ var DashCard = class DashCard extends LitElement {
49
67
  this.hasSlottedControls = false;
50
68
  this.hasFooter = false;
51
69
  this.dashboard = void 0;
70
+ this.leaving = false;
71
+ this.enterPending = false;
52
72
  }
53
73
  static {
54
74
  this.styles = unsafeCSS(dash_card_default);
@@ -73,6 +93,7 @@ var DashCard = class DashCard extends LitElement {
73
93
  disconnectedCallback() {
74
94
  this.dashboard?.unregisterCard(this);
75
95
  this.dashboard = void 0;
96
+ this.motion = void 0;
76
97
  super.disconnectedCallback();
77
98
  }
78
99
  /** Called by the grid when its shape or its layout record changed. */
@@ -80,14 +101,129 @@ var DashCard = class DashCard extends LitElement {
80
101
  this.requestUpdate();
81
102
  }
82
103
  willUpdate() {
83
- const visible = this.dashboard?.placementOf(this.cardId)?.visible;
84
- if (visible !== void 0) this.hidden = !visible;
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
+ this.syncVisibility();
85
111
  }
86
112
  updated() {
87
113
  const placement = this.placement;
88
114
  this.style.setProperty("--_grid-column", `${placement.col} / span ${placement.colSpan}`);
89
115
  this.style.setProperty("--_grid-row", `${placement.row} / span ${placement.rowSpan}`);
90
116
  this.syncHandleValues();
117
+ if (this.enterPending) {
118
+ this.enterPending = false;
119
+ this.playEnter();
120
+ }
121
+ }
122
+ /**
123
+ * Applies the layout record's `visible`. Hiding is deferred until the leave animation has played; showing again
124
+ * cancels a leave in flight and animates in. Before the first render, and outside a grid, nothing animates.
125
+ */
126
+ syncVisibility() {
127
+ const visible = this.dashboard?.placementOf(this.cardId)?.visible;
128
+ if (visible === void 0) return;
129
+ if (visible) {
130
+ if (this.leaving || this.motion) this.cancelMotion();
131
+ if (this.hidden && this.hasUpdated) this.enterPending = true;
132
+ this.hidden = false;
133
+ } else if (!this.hidden && !this.leaving) {
134
+ if (!this.hasUpdated) this.hidden = true;
135
+ else this.leave().then((done) => {
136
+ if (done) this.hidden = true;
137
+ });
138
+ }
139
+ }
140
+ /**
141
+ * Plays the leave animation, then removes the element from the document. Resolves once it is gone. The other
142
+ * cards keep their placement — the grid does not close the gap; re-place them (`col`/`row` or the grid's
143
+ * `layout`) once the promise resolves if it should.
144
+ */
145
+ async dismiss() {
146
+ if (!this.isConnected) return;
147
+ if (await this.leave()) this.remove();
148
+ }
149
+ get surface() {
150
+ return this.renderRoot.querySelector(".c2-dash-card");
151
+ }
152
+ /** Enter and leave timing, read back from the stylesheet so the variables and `prefers-reduced-motion` apply. */
153
+ timing(target, phase) {
154
+ const style = getComputedStyle(target);
155
+ return {
156
+ duration: style.transitionDuration.split(",").map((value) => parseDuration(value.trim()))[phase === "enter" ? 0 : 1] ?? 0,
157
+ easing: firstListEntry(style.transitionTimingFunction) || "ease"
158
+ };
159
+ }
160
+ cancelMotion() {
161
+ this.motion?.cancel();
162
+ this.motion = void 0;
163
+ this.leaving = false;
164
+ }
165
+ playEnter() {
166
+ if (isServer) return;
167
+ this.cancelMotion();
168
+ const target = this.surface;
169
+ if (!target || typeof target.animate !== "function") return;
170
+ const { duration, easing } = this.timing(target, "enter");
171
+ if (duration <= 0) return;
172
+ const motion = target.animate([{
173
+ opacity: 0,
174
+ transform: "scale(0.96)"
175
+ }, {
176
+ opacity: 1,
177
+ transform: "scale(1)"
178
+ }], {
179
+ duration,
180
+ easing
181
+ });
182
+ this.motion = motion;
183
+ motion.finished.then(() => {
184
+ if (this.motion === motion) this.motion = void 0;
185
+ }).catch(() => {});
186
+ }
187
+ /**
188
+ * Fades the card out. Resolves `true` once it has finished — the caller then hides or removes the element — and
189
+ * `false` when a return cancelled it. The end state is held (`fill: forwards`) until the next enter cancels it,
190
+ * so nothing flashes between the last frame and the hide.
191
+ */
192
+ async leave() {
193
+ if (this.motion) this.cancelMotion();
194
+ this.leaving = true;
195
+ await this.updateComplete;
196
+ if (!this.leaving) return false;
197
+ const target = this.surface;
198
+ if (isServer || !target || typeof target.animate !== "function") {
199
+ this.leaving = false;
200
+ return true;
201
+ }
202
+ const { duration, easing } = this.timing(target, "leave");
203
+ if (duration <= 0) {
204
+ this.leaving = false;
205
+ return true;
206
+ }
207
+ const motion = target.animate([{
208
+ opacity: 1,
209
+ transform: "scale(1)"
210
+ }, {
211
+ opacity: 0,
212
+ transform: "scale(0.96)"
213
+ }], {
214
+ duration,
215
+ easing,
216
+ fill: "forwards"
217
+ });
218
+ this.motion = motion;
219
+ try {
220
+ await motion.finished;
221
+ } catch {
222
+ return false;
223
+ }
224
+ if (this.motion !== motion) return false;
225
+ this.leaving = false;
226
+ return true;
91
227
  }
92
228
  /**
93
229
  * The splitter values are written straight onto the handles rather than re-rendered: a drag changes them on
@@ -103,26 +239,23 @@ var DashCard = class DashCard extends LitElement {
103
239
  handle.setAttribute("aria-valuenow", String(dashboard.splitterValue(axis, index)));
104
240
  }
105
241
  }
106
- /** `slotchange` does not fire for a server-rendered shadow root, so read every slot once. */
107
- firstUpdated() {
108
- for (const slot of this.renderRoot.querySelectorAll("slot")) this.updateSection(slot);
109
- }
110
242
  /**
111
243
  * The grid may upgrade after its cards do — the card element is in the document either way, so find it and wait
112
244
  * for the definition rather than for a parent that is already alive.
113
245
  */
114
- attachToDashboard() {
246
+ attachToDashboard(late = true) {
115
247
  const host = this.closest(DASHBOARD_TAG);
116
248
  if (!host) return;
117
249
  if (typeof host.registerCard !== "function") {
118
250
  if (isServer) return;
119
251
  customElements.whenDefined(DASHBOARD_TAG).then(() => {
120
- if (this.isConnected) this.attachToDashboard();
252
+ if (this.isConnected) this.attachToDashboard(false);
121
253
  });
122
254
  return;
123
255
  }
124
256
  this.dashboard = host;
125
257
  host.registerCard(this);
258
+ if (late && host.hasUpdated) this.enterPending = true;
126
259
  }
127
260
  get placement() {
128
261
  const override = this.dashboard?.placementOf(this.cardId);
@@ -271,7 +404,7 @@ var DashCard = class DashCard extends LitElement {
271
404
  `;
272
405
  }
273
406
  renderHandles() {
274
- if (!this.dashboard || this.resize === "none") return nothing;
407
+ if (!this.dashboard || this.resize === "none" || this.leaving) return nothing;
275
408
  const placement = this.placement;
276
409
  const horizontal = this.resize === "both" || this.resize === "horizontal";
277
410
  const vertical = this.resize === "both" || this.resize === "vertical";
@@ -348,6 +481,7 @@ __decorate([state()], DashCard.prototype, "hasActions", void 0);
348
481
  __decorate([state()], DashCard.prototype, "hasSlottedControls", void 0);
349
482
  __decorate([state()], DashCard.prototype, "hasFooter", void 0);
350
483
  __decorate([state()], DashCard.prototype, "dashboard", void 0);
484
+ __decorate([state()], DashCard.prototype, "leaving", void 0);
351
485
  DashCard = __decorate([customElement("c2-dash-card")], DashCard);
352
486
  //#endregion
353
487
  export { __decorate as n, DashCard as t };
package/dist/dash-card.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as DashCard } from "./dash-card-DYabhvcS.js";
1
+ import { t as DashCard } from "./dash-card-DNRGm1hM.js";
2
2
  export { DashCard };
package/dist/dashboard.js CHANGED
@@ -1,10 +1,10 @@
1
- import { n as __decorate } from "./dash-card-DYabhvcS.js";
1
+ import { n as __decorate } from "./dash-card-DNRGm1hM.js";
2
2
  import { LitElement, html, unsafeCSS } from "lit";
3
3
  import { property, state } from "lit/decorators.js";
4
4
  import { isServer } from "lit-html/is-server.js";
5
5
  import { customElement } from "@c2n/core/element-helper.js";
6
6
  //#region src/dashboard.scss?inline
7
- var dashboard_default = "/* ex : var((width: 24px), width, c2-checkbox) returns var(--c2-checkbox-width, 24px) */\n:host {\n display: grid;\n box-sizing: border-box;\n grid-template-columns: var(--_columns, 1fr);\n grid-template-rows: var(--_rows, auto);\n gap: var(--c2-dashboard--gap,8px);\n padding: var(--c2-dashboard--padding,0px);\n background: var(--c2-dashboard--background,transparent);\n border: var(--c2-dashboard--border,none);\n border-radius: var(--c2-dashboard--border-radius,0px);\n min-width: 0;\n min-height: 0;\n}\n\n:host([hidden]) {\n display: none;\n}\n\nslot {\n display: contents;\n}\n\n::slotted(*) {\n min-width: 0;\n min-height: 0;\n}";
7
+ var dashboard_default = "/* ex : var((width: 24px), width, c2-checkbox) returns var(--c2-checkbox-width, 24px) */\n:host {\n --_c2-dashboard-gap: var(--c2-dashboard--gap,8px);\n display: grid;\n box-sizing: border-box;\n grid-template-columns: var(--_columns, 1fr);\n grid-template-rows: var(--_rows, auto);\n gap: var(--c2-dashboard--gap,8px);\n padding: var(--c2-dashboard--padding,0px);\n background: var(--c2-dashboard--background,transparent);\n border: var(--c2-dashboard--border,none);\n border-radius: var(--c2-dashboard--border-radius,0px);\n min-width: 0;\n min-height: 0;\n}\n\n:host([hidden]) {\n display: none;\n}\n\nslot {\n display: contents;\n}\n\n::slotted(*) {\n min-width: 0;\n min-height: 0;\n}";
8
8
  //#endregion
9
9
  //#region src/dashboard.ts
10
10
  var FRACTION = /^([\d.]*)fr$/;
@@ -38,9 +38,15 @@ var Dashboard = class Dashboard extends LitElement {
38
38
  this.minRowHeight = 50;
39
39
  this.storageKey = void 0;
40
40
  this.layout = void 0;
41
+ this.layouts = void 0;
41
42
  this.columnTracks = [];
42
43
  this.rowTracks = [];
44
+ this.activeLayout = -1;
43
45
  this.cards = /* @__PURE__ */ new Set();
46
+ this.mediaQueries = [];
47
+ this.handleMediaChange = () => {
48
+ this.activeLayout = this.resolveActiveLayout();
49
+ };
44
50
  this.pixelCache = /* @__PURE__ */ new Map();
45
51
  }
46
52
  static {
@@ -60,22 +66,37 @@ var Dashboard = class Dashboard extends LitElement {
60
66
  get rowCount() {
61
67
  return this.rowTracks.length;
62
68
  }
69
+ /** The entry of `layouts` in force, or `undefined` while the authored grid is. */
70
+ get activeResponsiveLayout() {
71
+ return this.layouts?.[this.activeLayout];
72
+ }
73
+ connectedCallback() {
74
+ super.connectedCallback();
75
+ if (this.hasUpdated) this.watchMedia();
76
+ }
77
+ disconnectedCallback() {
78
+ super.disconnectedCallback();
79
+ this.unwatchMedia();
80
+ }
63
81
  willUpdate(changed) {
64
- if (!this.hasUpdated || changed.has("columns") || changed.has("rows") || changed.has("storageKey")) this.syncTracks();
82
+ if (!this.hasUpdated || changed.has("layouts")) this.watchMedia();
83
+ if (!this.hasUpdated || changed.has("columns") || changed.has("rows") || changed.has("storageKey") || changed.has("layouts") || changed.has("activeLayout")) this.syncTracks();
65
84
  }
66
85
  updated(changed) {
67
86
  this.pixelCache.clear();
68
87
  this.style.setProperty("--_columns", this.columnTracks.join(" "));
69
88
  this.style.setProperty("--_rows", this.rowTracks.join(" "));
70
- if (changed.has("columnTracks") || changed.has("rowTracks") || changed.has("layout")) for (const card of this.cards) card.hostChanged();
89
+ if (changed.has("columnTracks") || changed.has("rowTracks") || changed.has("layout") || changed.has("layouts") || changed.has("activeLayout")) for (const card of this.cards) card.hostChanged();
90
+ if (changed.has("activeLayout") && changed.get("activeLayout") !== void 0) this.emitLayoutChange();
71
91
  }
72
- /** Back to the authored tracks, and the stored ones are forgotten. */
92
+ /** Back to the authored tracks of the layout in force, and its stored ones are forgotten. */
73
93
  reset() {
74
- if (this.storageKey && !isServer) try {
75
- localStorage.removeItem(this.storageKey);
94
+ const key = this.activeStorageKey;
95
+ if (key && !isServer) try {
96
+ localStorage.removeItem(key);
76
97
  } catch {}
77
- this.columnTracks = toTracks(this.columns);
78
- this.rowTracks = toTracks(this.rows);
98
+ this.columnTracks = toTracks(this.activeResponsiveLayout?.columns ?? this.columns);
99
+ this.rowTracks = toTracks(this.activeResponsiveLayout?.rows ?? this.rows);
79
100
  this.emitLayoutChange();
80
101
  }
81
102
  registerCard(card) {
@@ -86,7 +107,13 @@ var Dashboard = class Dashboard extends LitElement {
86
107
  this.cards.delete(card);
87
108
  }
88
109
  placementOf(cardId) {
89
- return cardId ? this.layout?.[cardId] : void 0;
110
+ if (!cardId) return void 0;
111
+ const base = this.layout?.[cardId];
112
+ const active = this.activeResponsiveLayout?.layout?.[cardId];
113
+ return active && base ? {
114
+ ...base,
115
+ ...active
116
+ } : active ?? base;
90
117
  }
91
118
  resizeColumn(index, delta) {
92
119
  this.pixelCache.clear();
@@ -194,17 +221,46 @@ var Dashboard = class Dashboard extends LitElement {
194
221
  }
195
222
  return Math.max(0, min);
196
223
  }
224
+ /**
225
+ * One `MediaQueryList` per entry of `layouts`, listened to for as long as the element is connected. Whichever
226
+ * entry matches first is the one in force; the listeners re-run the choice whenever any of them flips.
227
+ */
228
+ watchMedia() {
229
+ this.unwatchMedia();
230
+ if (isServer || typeof matchMedia !== "function") return;
231
+ for (const entry of this.layouts ?? []) {
232
+ const query = matchMedia(entry.media);
233
+ query.addEventListener("change", this.handleMediaChange);
234
+ this.mediaQueries.push(query);
235
+ }
236
+ this.activeLayout = this.resolveActiveLayout();
237
+ }
238
+ unwatchMedia() {
239
+ for (const query of this.mediaQueries) query.removeEventListener("change", this.handleMediaChange);
240
+ this.mediaQueries = [];
241
+ }
242
+ resolveActiveLayout() {
243
+ return this.mediaQueries.findIndex((query) => query.matches);
244
+ }
245
+ /** Each entry of `layouts` stores its own sizes: `<storage-key>@<media>`; the authored grid uses the bare key. */
246
+ get activeStorageKey() {
247
+ if (!this.storageKey) return void 0;
248
+ const active = this.activeResponsiveLayout;
249
+ return active ? `${this.storageKey}@${active.media}` : this.storageKey;
250
+ }
197
251
  syncTracks() {
198
- const columns = toTracks(this.columns);
199
- const rows = toTracks(this.rows);
252
+ const active = this.activeResponsiveLayout;
253
+ const columns = toTracks(active?.columns ?? this.columns);
254
+ const rows = toTracks(active?.rows ?? this.rows);
200
255
  const stored = this.readStored();
201
256
  this.columnTracks = stored?.columns?.length === columns.length ? [...stored.columns] : columns;
202
257
  this.rowTracks = stored?.rows?.length === rows.length ? [...stored.rows] : rows;
203
258
  }
204
259
  readStored() {
205
- if (!this.storageKey || isServer) return null;
260
+ const key = this.activeStorageKey;
261
+ if (!key || isServer) return null;
206
262
  try {
207
- const raw = localStorage.getItem(this.storageKey);
263
+ const raw = localStorage.getItem(key);
208
264
  if (!raw) return null;
209
265
  const parsed = JSON.parse(raw);
210
266
  return parsed && typeof parsed === "object" ? parsed : null;
@@ -213,9 +269,10 @@ var Dashboard = class Dashboard extends LitElement {
213
269
  }
214
270
  }
215
271
  persist() {
216
- if (!this.storageKey || isServer) return;
272
+ const key = this.activeStorageKey;
273
+ if (!key || isServer) return;
217
274
  try {
218
- localStorage.setItem(this.storageKey, JSON.stringify({
275
+ localStorage.setItem(key, JSON.stringify({
219
276
  columns: this.columnTracks,
220
277
  rows: this.rowTracks
221
278
  }));
@@ -237,8 +294,10 @@ __decorate([property({
237
294
  })], Dashboard.prototype, "minRowHeight", void 0);
238
295
  __decorate([property({ attribute: "storage-key" })], Dashboard.prototype, "storageKey", void 0);
239
296
  __decorate([property({ attribute: false })], Dashboard.prototype, "layout", void 0);
297
+ __decorate([property({ attribute: false })], Dashboard.prototype, "layouts", void 0);
240
298
  __decorate([state()], Dashboard.prototype, "columnTracks", void 0);
241
299
  __decorate([state()], Dashboard.prototype, "rowTracks", void 0);
300
+ __decorate([state()], Dashboard.prototype, "activeLayout", void 0);
242
301
  Dashboard = __decorate([customElement("c2-dashboard")], Dashboard);
243
302
  //#endregion
244
303
  export { Dashboard };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c2n/dashboard",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "type": "module",
5
5
  "main": "dist/dashboard.js",
6
6
  "exports": {
@@ -29,6 +29,7 @@
29
29
  "files": [
30
30
  "dist",
31
31
  "types",
32
+ "custom-elements.json",
32
33
  "react.d.ts",
33
34
  "react.js",
34
35
  "vue.d.ts",
@@ -73,12 +74,12 @@
73
74
  }
74
75
  },
75
76
  "dependencies": {
76
- "@c2n/core": "0.0.11",
77
+ "@c2n/core": "0.0.13",
77
78
  "lit": "3.3.3"
78
79
  },
79
80
  "devDependencies": {
80
81
  "@c2n/config": "*"
81
82
  },
82
83
  "customElements": "custom-elements.json",
83
- "gitHead": "bf962fba5e49a0ac7555a082584e262949d323a5"
84
+ "gitHead": "aa19b641f64fbc54c36b7649a8171d7a686abbdd"
84
85
  }
package/react.d.ts CHANGED
@@ -6,6 +6,10 @@
6
6
  //
7
7
  // Register the elements at module scope before React renders, or React writes an object prop as an
8
8
  // attribute and it stringifies.
9
+ //
10
+ // On a server-rendered page (Next.js, React Router SSR) write a camelCase property by its kebab-case attribute
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.
9
13
 
10
14
  import type { DetailedHTMLProps, HTMLAttributes } from 'react'
11
15
  import type { DashCard } from '@c2n/dashboard/dash-card.js'
@@ -13,12 +17,27 @@ import type { Dashboard } from '@c2n/dashboard'
13
17
 
14
18
  /** Standard React host-element attributes plus the element's own public properties. */
15
19
  type C2Props<T> = DetailedHTMLProps<HTMLAttributes<T>, T> & Partial<Omit<T, keyof HTMLElement>>
20
+ /** What React writes to a custom element's attribute: true becomes the empty string, false removes it. */
21
+ type Attribute = string | number | boolean
16
22
 
17
23
  declare module 'react' {
18
24
  namespace JSX {
19
25
  interface IntrinsicElements {
20
- 'c2-dash-card': C2Props<DashCard>
21
- 'c2-dashboard': C2Props<Dashboard>
26
+ 'c2-dash-card': C2Props<DashCard> & {
27
+ 'card-id'?: Attribute
28
+ 'col-span'?: Attribute
29
+ 'row-span'?: Attribute
30
+ 'min-width'?: Attribute
31
+ 'min-height'?: Attribute
32
+ 'expand-width'?: Attribute
33
+ 'expand-height'?: Attribute
34
+ 'expand-full'?: Attribute
35
+ }
36
+ 'c2-dashboard': C2Props<Dashboard> & {
37
+ 'min-column-width'?: Attribute
38
+ 'min-row-height'?: Attribute
39
+ 'storage-key'?: Attribute
40
+ }
22
41
  }
23
42
  }
24
43
  }
@@ -28,15 +28,22 @@ export interface DashCard {
28
28
  * it, or focus it and use the arrow keys (10px a step, 1px with Shift).
29
29
  *
30
30
  * Filling the `header`, `actions` or `footer` slot turns on that row; with the header and actions both empty the
31
- * expand controls float over the top-right corner of the pane instead. An expanded card covers its neighbours, so
32
- * give it — or the card inside it — a background.
31
+ * expand controls float over the top-right corner of the pane instead. An expanded card covers its neighbours on
32
+ * an opaque `--c2-dash-card__expanded--background` (the theme's surface colour), while the card itself stays
33
+ * transparent at rest.
34
+ *
35
+ * A card that arrives while the grid is already on screen fades and scales in; one that leaves — through the
36
+ * grid's `layout` record (`visible: false`) or through `dismiss()`, which removes the element once the animation
37
+ * has played — fades out the same way. Cards present at load do not animate, and `prefers-reduced-motion` turns
38
+ * both off.
33
39
  *
34
40
  * Every built-in icon is a slot whose fallback is the default drawing, so a pane can use the host application's own
35
41
  * icon set without giving up the behaviour.
36
42
  *
37
43
  * @tag c2-dash-card
38
44
  *
39
- * @slot - Pane content. Give it `height: 100%` (a `c2-card` already stretches) so it follows the row track.
45
+ * @slot - Pane content. It fills the pane: the body is a column flex box and every slotted child is a `flex: 1`
46
+ * item with `min-height: 0`, so a chart or an editor follows the row track without a `height: 100%` chain.
40
47
  * @slot header - Title area of the header row; filling it turns the row on.
41
48
  * @slot actions - Your own controls at the end of the header row, before the built-in expand buttons and separated
42
49
  * from them by `--c2-dash-card__actions--gap`.
@@ -72,9 +79,13 @@ export interface DashCard {
72
79
  * @cssproperty {overflow} [--c2-dash-card--overflow=hidden] - `hidden` keeps the content inside the track; switch
73
80
  * it to `visible` for a pane that has to overflow, such as one holding a menu.
74
81
  *
75
- * @cssproperty {background} --c2-dash-card__expanded--background - Fill while the card is expanded over its
76
- * neighbours; falls back to `--c2-dash-card--background`, which is transparent, so set one of the two.
82
+ * @cssproperty {background} [--c2-dash-card__expanded--background=#ffffff] - Fill while the card is expanded over
83
+ * its neighbours, so they do not show through; the card's own `background` stays transparent.
77
84
  * @cssproperty {number} [--c2-dash-card__expanded--z-index=20]
85
+ * @cssproperty {duration} [--c2-dash-card__enter--animation-duration=200ms] - Fade and scale-in of a card added to
86
+ * a grid that is already on screen, or shown again through the layout record. `0ms` disables it.
87
+ * @cssproperty {duration} [--c2-dash-card__leave--animation-duration=160ms] - Fade-out before a card is hidden by
88
+ * the layout record or removed by `dismiss()`. `0ms` disables it.
78
89
  * @cssproperty {duration} [--c2-dash-card__expanded--animation-duration=200ms] - Length of the scale-in the card
79
90
  * plays when it expands or collapses. Ignored under `prefers-reduced-motion`.
80
91
  *
@@ -112,8 +123,8 @@ export interface DashCard {
112
123
  * @cssproperty {outline} [--c2-dash-card__control__focus--outline=2px solid rgba(2, 101, 220, 0.4)]
113
124
  * @cssproperty {pixel} [--c2-dash-card__control__focus--outline-offset=2px]
114
125
  *
115
- * @cssproperty {pixel} [--c2-dash-card__handle--size=6px] - Thickness of the grab area on an edge. It reaches into
116
- * the pane, so it stays grabbable however wide the grid gutter is.
126
+ * @cssproperty {pixel} [--c2-dash-card__handle--size=6px] - Smallest thickness of the grab area on an edge. Inside a
127
+ * grid the handle is as thick as the gutter when that is wider, centred on the edge, so the whole gutter drags.
117
128
  * @cssproperty {pixel} [--c2-dash-card__handle--inset=2px] - Gap between the handle's visible bar and the ends of
118
129
  * the edge.
119
130
  * @cssproperty {background} [--c2-dash-card__handle--background=transparent]
@@ -154,6 +165,12 @@ export declare class DashCard extends LitElement {
154
165
  private hasSlottedControls;
155
166
  private hasFooter;
156
167
  private dashboard;
168
+ /** `true` while the leave animation plays: the handles are gone, the placement is kept until it ends. */
169
+ private leaving;
170
+ /** The enter or leave animation in flight — or the finished leave, kept so a return can cancel its fill. */
171
+ private motion;
172
+ /** Set when the card should animate in after its next render. */
173
+ private enterPending;
157
174
  /** The grid reads this during a drag; a hidden card asks for nothing. */
158
175
  get constraint(): DashCardConstraint | undefined;
159
176
  connectedCallback(): void;
@@ -162,13 +179,33 @@ export declare class DashCard extends LitElement {
162
179
  hostChanged(): void;
163
180
  willUpdate(): void;
164
181
  updated(): void;
182
+ /**
183
+ * Applies the layout record's `visible`. Hiding is deferred until the leave animation has played; showing again
184
+ * cancels a leave in flight and animates in. Before the first render, and outside a grid, nothing animates.
185
+ */
186
+ private syncVisibility;
187
+ /**
188
+ * Plays the leave animation, then removes the element from the document. Resolves once it is gone. The other
189
+ * cards keep their placement — the grid does not close the gap; re-place them (`col`/`row` or the grid's
190
+ * `layout`) once the promise resolves if it should.
191
+ */
192
+ dismiss(): Promise<void>;
193
+ private get surface();
194
+ /** Enter and leave timing, read back from the stylesheet so the variables and `prefers-reduced-motion` apply. */
195
+ private timing;
196
+ private cancelMotion;
197
+ private playEnter;
198
+ /**
199
+ * Fades the card out. Resolves `true` once it has finished — the caller then hides or removes the element — and
200
+ * `false` when a return cancelled it. The end state is held (`fill: forwards`) until the next enter cancels it,
201
+ * so nothing flashes between the last frame and the hide.
202
+ */
203
+ private leave;
165
204
  /**
166
205
  * The splitter values are written straight onto the handles rather than re-rendered: a drag changes them on
167
206
  * every pointer move, and nothing else about the card changes with them.
168
207
  */
169
208
  private syncHandleValues;
170
- /** `slotchange` does not fire for a server-rendered shadow root, so read every slot once. */
171
- firstUpdated(): void;
172
209
  /**
173
210
  * The grid may upgrade after its cards do — the card element is in the document either way, so find it and wait
174
211
  * for the definition rather than for a parent that is already alive.
@@ -1 +1 @@
1
- {"version":3,"file":"dash-card.d.ts","sourceRoot":"","sources":["../../src/dash-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAiC,KAAK,cAAc,EAAE,MAAM,KAAK,CAAA;AAKpF,OAAO,KAAK,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AAChG,OAAO,EAAiB,KAAK,kBAAkB,EAAsB,MAAM,kBAAkB,CAAA;AAG7F,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,YAAY,GAAG,UAAU,GAAG,MAAM,CAAA;AAExE,gEAAgE;AAChE,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEnE,2CAA2C;AAC3C,MAAM,WAAW,0BAA0B;IACzC,+BAA+B;IAC/B,QAAQ,EAAE,gBAAgB,CAAA;CAC3B;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,WAAW,CAAC,0BAA0B,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,qBAAqB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAA;IACnE,mBAAmB,EAAE,wBAAwB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAA;CAC1E;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwGG;AACH,qBACa,QAAS,SAAQ,UAAU;IACtC,OAAgB,MAAM,0BAAoB;IAE1C,yDAAyD;IACrB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAY;IAE1E,yCAAyC;IACb,GAAG,SAAI;IAEnC,sCAAsC;IACV,GAAG,SAAI;IAEnC,2CAA2C;IACQ,OAAO,SAAI;IAE9D,wCAAwC;IACW,OAAO,SAAI;IAE9D,kGAAkG;IAC9C,QAAQ,SAAI;IAEhE,gGAAgG;IAC3C,SAAS,SAAI;IAElE,uCAAuC;IACV,MAAM,EAAE,cAAc,CAAS;IAE5D,kEAAkE;IACV,WAAW,UAAQ;IAE3E,+DAA+D;IACN,YAAY,UAAQ;IAE7E,kEAAkE;IACX,UAAU,UAAQ;IAEzE,0GAA0G;IAC7E,QAAQ,EAAE,gBAAgB,CAAS;IAEvD,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,UAAU,CAAQ;IAC1B,OAAO,CAAC,kBAAkB,CAAQ;IAClC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,SAAS,CAAuC;IAEjE,yEAAyE;IACzE,IAAI,UAAU,IAAI,kBAAkB,GAAG,SAAS,CAW/C;IAEQ,iBAAiB;IAKjB,oBAAoB;IAM7B,sEAAsE;IACtE,WAAW;IAIF,UAAU;IAKV,OAAO;IAOhB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAWxB,6FAA6F;IACpF,YAAY;IAIrB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAczB,OAAO,KAAK,SAAS,GAuBpB;IAED,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,SAAS;IA+BjB,OAAO,CAAC,mBAAmB;IAe3B,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,cAAc;IAsCtB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,aAAa;IAkBZ,MAAM;CAsBhB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,QAAQ,CAAA;KACzB;CACF"}
1
+ {"version":3,"file":"dash-card.d.ts","sourceRoot":"","sources":["../../src/dash-card.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,8 @@ export interface DashCardConstraint {
28
28
  export interface DashboardHost extends HTMLElement {
29
29
  readonly columnCount: number;
30
30
  readonly rowCount: number;
31
+ /** `true` once the grid has rendered; a card that registers after that arrived at runtime and animates in. */
32
+ readonly hasUpdated: boolean;
31
33
  registerCard(card: DashboardCard): void;
32
34
  unregisterCard(card: DashboardCard): void;
33
35
  /** Resizes one column by `delta` pixels, clamped by the minimums; returns the change that was actually applied. */
@@ -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,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,iFAAiF;IACjF,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAA;IACnD,uEAAuE;IACvE,WAAW,IAAI,IAAI,CAAA;CACpB;AAED,eAAO,MAAM,aAAa,iBAAiB,CAAA"}
@@ -18,6 +18,20 @@ export interface Dashboard {
18
18
  addEventListener: TypedAddEventListener<Dashboard, DashboardEventMap>;
19
19
  removeEventListener: TypedRemoveEventListener<Dashboard, DashboardEventMap>;
20
20
  }
21
+ /**
22
+ * One responsive variant of the grid. The first entry of `layouts` whose media query matches is applied over the
23
+ * authored `columns`, `rows` and `layout`; with none matching the authored ones stand.
24
+ */
25
+ export interface DashboardResponsiveLayout {
26
+ /** Media query, as given to `matchMedia`: `'(max-width: 1279px)'`. */
27
+ media: string;
28
+ /** Column tracks while this entry is active; the authored `columns` otherwise. */
29
+ columns?: number | string | string[];
30
+ /** Row tracks while this entry is active; the authored `rows` otherwise. */
31
+ rows?: number | string | string[];
32
+ /** Placement overrides by `card-id`, merged per card over the grid's `layout`. */
33
+ layout?: Record<string, DashCardPlacement>;
34
+ }
21
35
  /**
22
36
  * Grid of resizable panes. The children are `c2-dash-card` elements, placed by their `col`/`row` attributes; each
23
37
  * one draws drag handles on the edges it shares with a neighbour, and dragging one resizes the whole track, so the
@@ -26,6 +40,15 @@ export interface Dashboard {
26
40
  * the `fr` tracks around it give up the space in proportion to their weight, down to the minimums. With a
27
41
  * `storage-key` the sizes survive a reload.
28
42
  *
43
+ * `layouts` makes the grid responsive without a remount: each entry names a media query and the tracks and card
44
+ * placements to use while it matches, the first match wins, and every entry keeps its own stored sizes under
45
+ * `<storage-key>@<media>`.
46
+ *
47
+ * Placement is the application's: the grid never re-places cards on its own. A pane removed or hidden at runtime
48
+ * leaves its cells empty and its neighbours where they were, and a pane added at runtime lands exactly where its
49
+ * `col`/`row` say, on top of whatever is already there if that cell is taken. To close a gap, or to make room, set
50
+ * the cards' `col`/`row`/`col-span`/`row-span` or hand the grid a `layout` record — both are applied in place.
51
+ *
29
52
  * The grid is the sizing authority: a card never sets its own width. Give the element a height (or place it in a
30
53
  * flex/grid parent that does) whenever the rows use `fr`, since the row tracks divide the host's height.
31
54
  *
@@ -33,11 +56,11 @@ export interface Dashboard {
33
56
  *
34
57
  * @slot - The `c2-dash-card` panes. Anything else becomes an ordinary grid item, placed by your own CSS.
35
58
  *
36
- * @event {CustomEvent<DashboardLayoutChangeDetail>} layout-change - The track sizes changed and the gesture ended.
37
- * Does not bubble: listen on the element.
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.
38
61
  *
39
- * @cssproperty {pixel} [--c2-dashboard--gap=8px] - Gutter between the cards. The drag handles sit inside the cards,
40
- * so a gutter under ~6px is hard to grab.
62
+ * @cssproperty {pixel} [--c2-dashboard--gap=8px] - Gutter between the cards. The whole gutter drags: each card's
63
+ * handle is centred on its edge and as thick as the gap (never under `--c2-dash-card__handle--size`).
41
64
  * @cssproperty {padding} [--c2-dashboard--padding=0px] - Inset around the tracks. With a `background` it is what
42
65
  * turns the gutters into a visible frame between the panes.
43
66
  * @cssproperty {background} [--c2-dashboard--background=transparent]
@@ -58,12 +81,23 @@ export declare class Dashboard extends LitElement {
58
81
  storageKey: string | undefined;
59
82
  /**
60
83
  * Placement overrides keyed by the cards' `card-id`, for a layout that is chosen at runtime rather than authored
61
- * in the markup. Each entry wins over the card's own `col`/`row`/`col-span`/`row-span`/visibility.
84
+ * in the markup. Each entry wins over the card's own `col`/`row`/`col-span`/`row-span`/visibility. This is also
85
+ * how an app re-flows the remaining panes after one was removed: the grid does not do that by itself.
62
86
  */
63
87
  layout: Record<string, DashCardPlacement> | undefined;
88
+ /**
89
+ * Responsive variants, in priority order: the first entry whose `media` matches supplies the tracks and the card
90
+ * placements, and the grid switches as the viewport crosses a breakpoint. Nothing is stored across entries — each
91
+ * one keeps its own sizes under `<storage-key>@<media>`.
92
+ */
93
+ layouts: DashboardResponsiveLayout[] | undefined;
64
94
  private columnTracks;
65
95
  private rowTracks;
96
+ /** Index into `layouts` of the entry in force, `-1` for the authored grid. */
97
+ private activeLayout;
66
98
  private cards;
99
+ private mediaQueries;
100
+ private readonly handleMediaChange;
67
101
  /** Used track sizes, valid until the next write to the tracks. */
68
102
  private pixelCache;
69
103
  /** Column tracks as they are laid out right now. */
@@ -72,9 +106,13 @@ export declare class Dashboard extends LitElement {
72
106
  get rowSizes(): string[];
73
107
  get columnCount(): number;
74
108
  get rowCount(): number;
109
+ /** The entry of `layouts` in force, or `undefined` while the authored grid is. */
110
+ get activeResponsiveLayout(): DashboardResponsiveLayout | undefined;
111
+ connectedCallback(): void;
112
+ disconnectedCallback(): void;
75
113
  protected willUpdate(changed: PropertyValues): void;
76
114
  protected updated(changed: PropertyValues): void;
77
- /** Back to the authored tracks, and the stored ones are forgotten. */
115
+ /** Back to the authored tracks of the layout in force, and its stored ones are forgotten. */
78
116
  reset(): void;
79
117
  registerCard(card: DashboardCard): void;
80
118
  unregisterCard(card: DashboardCard): void;
@@ -98,6 +136,15 @@ export declare class Dashboard extends LitElement {
98
136
  private resizeTrack;
99
137
  /** The largest minimum any card covering this track asks for, spread over the tracks that card spans. */
100
138
  private trackMin;
139
+ /**
140
+ * One `MediaQueryList` per entry of `layouts`, listened to for as long as the element is connected. Whichever
141
+ * entry matches first is the one in force; the listeners re-run the choice whenever any of them flips.
142
+ */
143
+ private watchMedia;
144
+ private unwatchMedia;
145
+ private resolveActiveLayout;
146
+ /** Each entry of `layouts` stores its own sizes: `<storage-key>@<media>`; the authored grid uses the bare key. */
147
+ private get activeStorageKey();
101
148
  private syncTracks;
102
149
  private readStored;
103
150
  private persist;
@@ -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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"}