@nldd/design-system 0.8.85 → 0.8.86

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.
Files changed (80) hide show
  1. package/custom-elements.json +156 -18
  2. package/dist/components/components.js +406 -128
  3. package/dist/components/layout/collection/collection.d.ts +15 -8
  4. package/dist/components/layout/collection/collection.d.ts.map +1 -1
  5. package/dist/components/layout/collection/collection.js +38 -13
  6. package/dist/components/layout/collection/collection.js.map +1 -1
  7. package/dist/components/layout/collection/collection.styles.d.ts.map +1 -1
  8. package/dist/components/layout/collection/collection.styles.js +36 -23
  9. package/dist/components/layout/collection/collection.styles.js.map +1 -1
  10. package/dist/components/layout/container/container.d.ts +11 -3
  11. package/dist/components/layout/container/container.d.ts.map +1 -1
  12. package/dist/components/layout/container/container.js +30 -17
  13. package/dist/components/layout/container/container.js.map +1 -1
  14. package/dist/components/layout/container/container.styles.d.ts.map +1 -1
  15. package/dist/components/layout/container/container.styles.js +19 -21
  16. package/dist/components/layout/container/container.styles.js.map +1 -1
  17. package/dist/components/layout/page/page.d.ts +23 -2
  18. package/dist/components/layout/page/page.d.ts.map +1 -1
  19. package/dist/components/layout/page/page.js +56 -2
  20. package/dist/components/layout/page/page.js.map +1 -1
  21. package/dist/components/layout/page/page.styles.d.ts.map +1 -1
  22. package/dist/components/layout/page/page.styles.js +33 -8
  23. package/dist/components/layout/page/page.styles.js.map +1 -1
  24. package/dist/components/layout/page-sections/sidebar-section/sidebar-section.styles.d.ts.map +1 -1
  25. package/dist/components/layout/page-sections/sidebar-section/sidebar-section.styles.js +7 -5
  26. package/dist/components/layout/page-sections/sidebar-section/sidebar-section.styles.js.map +1 -1
  27. package/dist/components/layout/sheet/sheet.styles.js +2 -2
  28. package/dist/components/layout/split-views/bar-split-view/bar-split-view.d.ts +1 -1
  29. package/dist/components/layout/split-views/bar-split-view/bar-split-view.d.ts.map +1 -1
  30. package/dist/components/layout/split-views/bar-split-view/bar-split-view.js +13 -13
  31. package/dist/components/layout/split-views/bar-split-view/bar-split-view.js.map +1 -1
  32. package/dist/components/layout/split-views/bar-split-view/bar-split-view.styles.js +1 -1
  33. package/dist/components/lists-and-tables/list/list.d.ts +13 -3
  34. package/dist/components/lists-and-tables/list/list.d.ts.map +1 -1
  35. package/dist/components/lists-and-tables/list/list.js +39 -3
  36. package/dist/components/lists-and-tables/list/list.js.map +1 -1
  37. package/dist/components/lists-and-tables/list/list.styles.d.ts.map +1 -1
  38. package/dist/components/lists-and-tables/list/list.styles.js +8 -1
  39. package/dist/components/lists-and-tables/list/list.styles.js.map +1 -1
  40. package/dist/components/lists-and-tables/list/list.template.d.ts +4 -1
  41. package/dist/components/lists-and-tables/list/list.template.d.ts.map +1 -1
  42. package/dist/components/lists-and-tables/list/list.template.js +31 -12
  43. package/dist/components/lists-and-tables/list/list.template.js.map +1 -1
  44. package/dist/components/lists-and-tables/list-item/list-item.d.ts +8 -3
  45. package/dist/components/lists-and-tables/list-item/list-item.d.ts.map +1 -1
  46. package/dist/components/lists-and-tables/list-item/list-item.js +35 -9
  47. package/dist/components/lists-and-tables/list-item/list-item.js.map +1 -1
  48. package/dist/components/lists-and-tables/list-item/list-item.template.d.ts +1 -1
  49. package/dist/components/lists-and-tables/list-item/list-item.template.d.ts.map +1 -1
  50. package/dist/components/lists-and-tables/list-item/list-item.template.js +18 -1
  51. package/dist/components/lists-and-tables/list-item/list-item.template.js.map +1 -1
  52. package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.d.ts.map +1 -1
  53. package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.js +50 -12
  54. package/dist/components/navigation/top-navigation-bar/top-navigation-bar.styles.js.map +1 -1
  55. package/dist/components/status-and-feedback/modal-dialog/modal-dialog.styles.js +3 -3
  56. package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.d.ts.map +1 -1
  57. package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.js +15 -0
  58. package/dist/components/status-and-feedback/progress-circle/progress-circle.styles.js.map +1 -1
  59. package/dist/components/status-and-feedback/progress-circle/progress-circle.template.d.ts.map +1 -1
  60. package/dist/components/status-and-feedback/progress-circle/progress-circle.template.js +4 -3
  61. package/dist/components/status-and-feedback/progress-circle/progress-circle.template.js.map +1 -1
  62. package/dist/components/visibility-mixin-BU1vIMW7.js +161 -0
  63. package/dist/favicon.svg +4 -0
  64. package/dist/nldd.min.js +775 -646
  65. package/dist/touch-icon.png +0 -0
  66. package/dist/types/vue.d.ts +24 -10
  67. package/dist/utilities/spacing-scale.d.ts +26 -0
  68. package/dist/utilities/spacing-scale.d.ts.map +1 -0
  69. package/dist/utilities/spacing-scale.js +54 -0
  70. package/dist/utilities/spacing-scale.js.map +1 -0
  71. package/dist/utilities/visibility-mixin.d.ts +11 -8
  72. package/dist/utilities/visibility-mixin.d.ts.map +1 -1
  73. package/dist/utilities/visibility-mixin.js +58 -45
  74. package/dist/utilities/visibility-mixin.js.map +1 -1
  75. package/dist/utilities/visibility-mixin.styles.d.ts +14 -0
  76. package/dist/utilities/visibility-mixin.styles.d.ts.map +1 -0
  77. package/dist/utilities/visibility-mixin.styles.js +52 -0
  78. package/dist/utilities/visibility-mixin.styles.js.map +1 -0
  79. package/package.json +5 -2
  80. package/dist/components/visibility-mixin-vbfhyo7f.js +0 -104
Binary file
@@ -583,7 +583,7 @@ declare module 'vue' {
583
583
  };
584
584
 
585
585
  type NLDDCollectionProps = {
586
- /** Layout mode: 'grid' | 'stack' | 'horizontal-scroll' (default: 'grid') */
586
+ /** Layout mode: 'grid' | 'stack' | 'lanes' | 'horizontal-scroll' (default: 'grid') */
587
587
  'layout'?: NLDDCollection['layout'];
588
588
  /** Show load-more button in grid/stack (default: false) */
589
589
  'show-load-more'?: NLDDCollection['showLoadMore'];
@@ -597,12 +597,24 @@ declare module 'vue' {
597
597
  'lazy-load'?: NLDDCollection['lazyLoad'];
598
598
  /** Automatically load more items when the button becomes visible */
599
599
  'lazyLoad'?: NLDDCollection['lazyLoad'];
600
- /** Preferred width for each item (e.g. '280px', '20rem'). In grid layout used as the minimum column width (columns will be at least this wide; 1fr if container allows more). In horizontal scroll used as flex-basis. Never forces horizontal overflow — the value is clamped to container width. */
600
+ /** Preferred width for each item (e.g. '280px', '20rem'). In grid and lanes layouts used as the minimum column width (columns will be at least this wide; 1fr if container allows more). In horizontal scroll used as flex-basis. Never forces horizontal overflow — the value is clamped to container width. */
601
601
  'item-width'?: NLDDCollection['itemWidth'];
602
- /** Preferred width for each item (e.g. '280px', '20rem'). In grid layout used as the minimum column width (columns will be at least this wide; 1fr if container allows more). In horizontal scroll used as flex-basis. Never forces horizontal overflow — the value is clamped to container width. */
602
+ /** Preferred width for each item (e.g. '280px', '20rem'). In grid and lanes layouts used as the minimum column width (columns will be at least this wide; 1fr if container allows more). In horizontal scroll used as flex-basis. Never forces horizontal overflow — the value is clamped to container width. */
603
603
  'itemWidth'?: NLDDCollection['itemWidth'];
604
- /** Custom gap between items (any CSS length, e.g. '8px'). Overrides the responsive default at every breakpoint; unset keeps the default. */
604
+ /** Gap between items, as a step of the spacing scale ('0', '2', '4', '6', '8', '10', '12', '16', '20', '24', '28', '32', '40', '44', '48', '56', '64', '80', '96'). Overrides the responsive default at every breakpoint; unset keeps the default. */
605
605
  'gap'?: NLDDCollection['gap'];
606
+ /** Gap at sm, overriding `gap` there */
607
+ 'sm-gap'?: NLDDCollection['smGap'];
608
+ /** Gap at sm, overriding `gap` there */
609
+ 'smGap'?: NLDDCollection['smGap'];
610
+ /** Gap at md, overriding `gap` there */
611
+ 'md-gap'?: NLDDCollection['mdGap'];
612
+ /** Gap at md, overriding `gap` there */
613
+ 'mdGap'?: NLDDCollection['mdGap'];
614
+ /** Gap at lg, overriding `gap` there */
615
+ 'lg-gap'?: NLDDCollection['lgGap'];
616
+ /** Gap at lg, overriding `gap` there */
617
+ 'lgGap'?: NLDDCollection['lgGap'];
606
618
  /** Translation overrides; unset keys fall back to Dutch. Available keys: 'components.collection.previous-action', 'components.collection.next-action', 'components.collection.load-more-action' */
607
619
  'translations'?: NLDDCollection['translations'];
608
620
  /** When the load-more button is clicked */
@@ -1529,7 +1541,9 @@ declare module 'vue' {
1529
1541
  'button'?: NLDDListItem['button'];
1530
1542
  /** Makes the whole row a `role="checkbox"` control. Wins over `button`, loses to `href`. */
1531
1543
  'checkbox'?: NLDDListItem['checkbox'];
1532
- /** Checked state of a `checkbox` row; the item toggles it on activation */
1544
+ /** Makes the whole row one radio of a group: the action becomes a `role="radio"` button carrying `aria-checked`, and activation sets `checked` (never clears it) and fires `change`. Put the rows in an `nldd-list type="radiogroup"`, which is what makes them a set. Wins over `button`, loses to `href` and `checkbox`. The arrow keys move focus without checking, where a native radio group and `nldd-radio-button-group` check as they go: a row can carry more than a label, so stepping past one should not commit it. */
1545
+ 'radio'?: NLDDListItem['radio'];
1546
+ /** Checked state of a `checkbox` or `radio` row. A checkbox row toggles it on activation, a radio row only ever sets it */
1533
1547
  'checked'?: NLDDListItem['checked'];
1534
1548
  /** Switches the row's own control off: a `button` or `checkbox` row stops responding and dims, a `href` row gets `aria-disabled` and its click is blocked (a link cannot be disabled natively). A row without a control of its own has nothing to switch off, and segments carry their own `disabled`. The arrow keys skip a disabled row. */
1535
1549
  'disabled'?: NLDDListItem['disabled'];
@@ -1548,7 +1562,7 @@ declare module 'vue' {
1548
1562
  'childRows'?: NLDDListItem['childRows'];
1549
1563
  /** The branch this row hangs under, or undefined for a top-level row. */
1550
1564
  'parentRow'?: NLDDListItem['parentRow'];
1551
- /** On a `checkbox` row after it toggles; detail: { checked: boolean } */
1565
+ /** On a `checkbox` row after it toggles, and on a `radio` row when it becomes checked; detail: { checked: boolean } */
1552
1566
  'onChange'?: (event: CustomEvent) => void;
1553
1567
  };
1554
1568
 
@@ -3622,11 +3636,11 @@ declare module 'vue' {
3622
3636
  'nldd-code-editor': DefineComponent<NLDDCodeEditorProps>;
3623
3637
  /** A read-only block of code/text built on a non-editable CodeMirror 6 view. Visually pairs with nldd-code-editor (same engine, same token palette). Whitespace is preserved; long lines scroll horizontally by default. Set `wrap` to break long lines onto the next visual line. Set `language` to one of the supported grammars (yaml, json, javascript, typescript, css, html, xml, bash, markdown, rust, gherkin, toml, sql, python) to highlight the content. Without `language` the content renders plain. Grammars are loaded lazily on first use, so a page that never sets `language` ships zero grammar code. Token colors are the `--components-code-viewer-token-*` custom properties (shared with the editor via the CodeMirror highlight style). Override them per-instance to swap the theme. */
3624
3638
  'nldd-code-viewer': DefineComponent<NLDDCodeViewerProps>;
3625
- /** A container for displaying collections of items. Supports grid, stack, and horizontal scroll layouts. In grid and stack modes, items are paginated via a load-more button. In horizontal scroll, the prev/next controls and the edge fade appear only when the items overflow the container. With `lazy-load`, the next items are automatically loaded when the load-more button comes into view. */
3639
+ /** A container for displaying collections of items. Supports grid, stack, lanes and horizontal scroll layouts. In grid and stack modes, items are paginated via a load-more button. In horizontal scroll, the prev/next controls and the edge fade appear only when the items overflow the container. With `lazy-load`, the next items are automatically loaded when the load-more button comes into view. */
3626
3640
  'nldd-collection': DefineComponent<NLDDCollectionProps>;
3627
3641
  /** A text input with autocomplete dropdown via nldd-menu. Add a slotted nldd-menu with nldd-menu-item children to provide options. The slotted nldd-menu keeps its default focus behavior (menu container receives focus) so that typing keeps focus on the input. The picker button moves focus to the menu explicitly on activation. Note: Only nldd-menu-item type="button" is supported. Radio and checkbox types are not supported in this context. */
3628
3642
  'nldd-combo-box': DefineComponent<NLDDComboBoxProps>;
3629
- /** A simple layout primitive: pick a layout mode, give it a gap, optionally align contents, and add padding. Padding can be set for all sides, per axis (inline/block), or per individual side. Specificity: per side > per axis > all sides. Responsive padding and gap have sm/md/lg variants. Each variant emits both an @media (viewport) and @container (layout-container) query. When inside a layout-container the @container query wins; otherwise the @media query provides the viewport-based fallback. Layout modes: - `stack` (default): block items, stacked vertically. The "what you expect from DOM flow" mode. - `row`: flex row, no wrapping. Items shrink or overflow. - `wrap`: flex row, items wrap to new lines. - `grid`: CSS grid, auto-fit columns at min 280px wide. - `columns`: CSS multi-column flow, 280px minimum column width, items don't split across column breaks. Alignment maps to the layout's natural axis: - `stack`: vertical = main-axis (justify-content), horizontal = cross-axis (align-items) - `row` / `wrap`: horizontal = main-axis, vertical = cross-axis - `grid`: horizontal = justify-items, vertical = align-items (per cell) - `columns`: alignment props have no effect (CSS multicol doesn't expose alignment) Item order is set per-child via attributes on the slotted children themselves: `<child order="3">` for a fixed position, or `<child sm-order="N">` / `<child md-order="N">` / `<child lg-order="N">` to override per breakpoint (resolved against THIS container's width via @container queries, same scope as the responsive padding/gap). The container observes slot changes and child attribute mutations and bridges these to `--_slot-order` / `--_slot-sm-order` / etc. custom properties on each child's inline style, which the container's CSS then reads via `::slotted(*)` inside @container queries. Cascade: `sm-order` falls back to `order` falls back to `0` at sm (and analogously for md/lg). No-op for `layout="columns"` (CSS multicol has no per-item ordering hook). The `column-count` attribute (1-8) forces an exact column count for `layout="grid"` (overrides auto-fit) and `layout="columns"` (overrides the natural width-driven count). `sm-column-count` / `md-column-count` / `lg-column-count` resolve against this container's OWN width via an `@container (...)` query on the host — not against the viewport. That lets a footer in a narrow sidebar choose its own column count independent of the surrounding page width. `layout="lanes"` packs items into balanced columns using native CSS grid lanes where supported, falling back to CSS multicol (column-order) elsewhere. CSS-only, no JS. Honours `gap` on both axes and `column-count`. */
3643
+ /** A simple layout primitive: pick a layout mode, give it a gap, optionally align contents, and add padding. Padding can be set for all sides, per axis (inline/block), or per individual side. Specificity: per side > per axis > all sides. Responsive padding and gap have sm/md/lg variants. Each variant emits both an @media (viewport) and @container (layout-container) query. When inside a layout-container the @container query wins; otherwise the @media query provides the viewport-based fallback. Layout modes: - `stack` (default): block items, stacked vertically. The "what you expect from DOM flow" mode. - `row`: flex row, no wrapping. Items shrink or overflow. - `wrap`: flex row, items wrap to new lines. - `grid`: CSS grid, auto-fit columns at min 280px wide. - `columns`: CSS multi-column flow, 280px minimum column width, items don't split across column breaks. Alignment maps to the layout's natural axis: - `stack`: vertical = main-axis (justify-content), horizontal = cross-axis (align-items) - `row` / `wrap`: horizontal = main-axis, vertical = cross-axis - `grid`: horizontal = justify-items, vertical = align-items (per cell) - `columns`: alignment props have no effect (CSS multicol doesn't expose alignment) Item order is set per-child via attributes on the slotted children themselves: `<child order="3">` for a fixed position, or `<child sm-order="N">` / `<child md-order="N">` / `<child lg-order="N">` to override per breakpoint (resolved against THIS container's width via @container queries, same scope as the responsive padding/gap). The container observes slot changes and child attribute mutations and bridges these to `--_slot-order` / `--_slot-sm-order` / etc. custom properties on each child's inline style, which the container's CSS then reads via `::slotted(*)` inside @container queries. Cascade: `sm-order` falls back to `order` falls back to `0` at sm (and analogously for md/lg). No-op for `layout="columns"` (CSS multicol has no per-item ordering hook). The `column-count` attribute (1-8) forces an exact column count for `layout="grid"` (overrides auto-fit) and `layout="columns"` (overrides the natural width-driven count). `sm-column-count` / `md-column-count` / `lg-column-count` resolve against this container's OWN width via an `@container (...)` query on the host — not against the viewport. That lets a footer in a narrow sidebar choose its own column count independent of the surrounding page width. `layout="lanes"` packs items into balanced columns using native CSS grid lanes where supported, falling back to CSS multicol (column-order) elsewhere. CSS-only, no JS. Honours `gap` on both axes and `column-count`. Note that nldd-collection's lanes falls back to its own grid rather than to multicol: that component pages, and multicol redistributes the whole set every time load-more adds to it. */
3630
3644
  'nldd-container': DefineComponent<NLDDContainerProps>;
3631
3645
  /** A text field for a date, with an optional calendar in a popover. The value is always ISO (yyyy-mm-dd); on screen it shows the Dutch notation (dd-mm-yyyy). Typing is not masked: input is accepted generously and normalized only when the field is left. Error messages belong to nldd-form-field, not here. This field reflects only `invalid` / `valid`, like nldd-text-field. */
3632
3646
  'nldd-date-field': DefineComponent<NLDDDateFieldProps>;
@@ -3674,7 +3688,7 @@ declare module 'vue' {
3674
3688
  'nldd-keyboard-shortcut': DefineComponent<NLDDKeyboardShortcutProps>;
3675
3689
  /** Hyperlink component with two modes: 1. **Standalone (sized)**: set `size="xs"|"sm"|"md"|"lg"` for menus, action areas or overviews. Fixed text size, `display: inline-flex` with `gap` for icon spacing. 2. **Inline (inherit)**: leave `size` out or set `size="inherit"` explicitly. The link inherits `font-size`, `line-height` and `font-family` from its surroundings. Text wraps naturally across lines (`display: inline`). Icons work here too; the natural whitespace between icon and text provides the spacing. For links in CMS or markdown output, where the `<a>` arrives as HTML, `<nldd-rich-text>` with a raw `<a>` remains the route to take. */
3676
3690
  'nldd-link': DefineComponent<NLDDLinkProps>;
3677
- /** A container for `nldd-list-item` elements. The `type` attribute switches the list's a11y role and behavior: - `list` (default) — `role="list"`, items `role="listitem"`. Reorderable allowed. - `tree` — `role="tree"`, items `role="treeitem"`. Branch rows put their child rows in their own `slot="children"`, which the item renders as a `role="group"`. Level, position and set size are NOT authored: the nesting represents the hierarchy, so assistive technology derives them. A branch row must carry `expanded`; the group is hidden while it is false. Visual indentation is the consumer's — repeat a spacer-cell per level. Comes with its own keyboard, see "Tree" below. - `navigation` — host `role="navigation"`, items with `selected` get `aria-current="page"` on their inner `<a>` or `<button>`. - `form` — rows that are not actions themselves: the controls inside them are. A row of a label and a field, a switch, a menu button, or a value you cannot change at all. Semantically the same as `list` (`role="list"`, `role="listitem"`), and everything visual is unchanged; what falls away is the keyboard of a list you walk through. No arrow navigation, so no promise of it either, and no tab stop on the row: Tab goes straight to the controls, in source order, the way it does in any form. Rows that ARE actions (`href`, `button`, `checkbox`, or a segment) contradict that and warn in development. SwiftUI draws the same line between `List` and `Form`, for the same reason. - `listbox` — an accessible, filterable listbox (combobox pattern). The list renders its OWN search input (`role="combobox"`) pinned above the options; `.list__items` becomes `role="listbox"` and items become `role="option"`. Focus stays in the input, the active option moves via `aria-activedescendant`, and filtering is consumer-managed via the `input` event (toggle `[hidden]` on items). See "Listbox" below. Selection state is consumer-managed: the list never mutates `selected` itself. A list you walk through answers to the arrow keys, and there is no attribute to switch that on. Whether the keys do something is not a property of one list: it is what a reader may assume about all of them, and a per-list setting made that unknowable from the outside. It follows the type, which you can see before you touch a key. - ArrowUp / ArrowDown — move focus between the rows there is something to do with. A row of nothing but text is skipped, because focus that leads nowhere is a dead end. - Home / End — the first / last of those rows. - Tab — the list is ONE tab stop, so Tab moves past it rather than through it. Within the current row Tab walks that row's own controls: a chevron beside a checkbox, a menu button at the end. The same controls in the other rows are held out of the tab order (`tabindex="-1"`, or `no-tab` on a design-system control that keeps its tab stop in its own shadow root), and so are this row's once focus leaves the list, so tabbing back in lands on the row again. - Escape — out of a control the row holds, back onto the row. One level up, where Shift+Tab is one step back. On the row itself the list claims nothing, so Escape carries on to whatever holds the list, and a control showing a menu keeps the first press for closing that menu. While focus sits in a control a row holds, the list stands down: those keys are the control's, and a list that took them anyway would pull focus out of a combo box or a text field mid-word. What the row IS — its own link, button or segments — keeps answering here. Arrows move focus only; selection stays consumer-managed. Three types answer differently, and all three say so on screen before you touch a key: a listbox runs its keyboard from its search field, a reorderable list moves rows with the arrows, and a form has no rows to move between at all. In `type="listbox"` the list owns a native `<input role="combobox">` (mirroring how `nldd-combo-box` wires an input to a slotted listbox). Keyboard, handled on the input so focus never leaves it: - ArrowDown / ArrowUp — move the active option among the VISIBLE (non-`[hidden]`) options (wrap around). - Home / End — first / last visible option. - Enter — activate the active option by triggering its inner action (a link navigates, a button fires the consumer's handler). Selection stays consumer-managed. - Escape — clear the search value (and refire `input`). On every active change the input's `aria-activedescendant` is set to the active option's id and the option is scrolled into view. The active option (`_highlighted` on the item, a highlight) is distinct from `selected`. Filtering is the consumer's job: listen to `input` (`{ detail: { value } }`) and toggle `[hidden]` on items; after the visible set changes the list resets the active option to the first visible one. `reorderable` and the roving arrow keys are ignored in listbox mode (listbox has its own keyboard). A tree adds to that keyboard, and counts the rows of an open branch as part of the order the arrows walk: - ArrowRight — opens a closed branch; on an open one it steps to its first child. - ArrowLeft — closes an open branch; on a leaf it steps out to the parent row. - Enter — follows the row: its own link or button, or on a segmented branch the first action that is not the chevron. A branch with only a chevron folds instead. - Space — open and close, the same as Right and Left. Only while focus sits on the row itself: a row that is its own control, and a segmented action you tabbed into, handle both keys themselves. Opening and closing runs through the row's own disclosure control — the segment marked `disclosure`, or the row itself when it is a button. The list activates that control rather than writing `expanded`, so the state keeps being set in one place: the consumer's handler. A row that is a link is never activated this way, since that would navigate away. The tree is one tab stop. Focus lands on the row itself when the row has no control of its own, because that is where `treeitem` sits and it makes assistive technology announce the row rather than a button inside it. Tab then walks the controls of THAT row (a chevron beside a checkbox, say) and leaves the list after the last one. A deliberate deviation: strictly speaking a row with several controls is a `treegrid`, not a `tree`. We keep the tree semantics — level and set size are what matters here, not rows and columns — and borrow the "Tab within the row" behavior from the grid pattern. Should a tree with real columns come up, that is when `treegrid` earns its own type. On reorder (type="list" + reorderable), the list dispatches `nldd-reorder` with `fromIndex` / `toIndex` and expects the consumer to mutate the DOM (or their data model that renders the DOM). Focus is restored to the moved item's drag handle via a single `requestAnimationFrame` — this assumes the consumer reorders **synchronously** in the event handler. Async renderers (React, Vue, …) that update the DOM on a later tick will miss the focus restore and should manage focus themselves after their render commits. */
3691
+ /** A container for `nldd-list-item` elements. The `type` attribute switches the list's a11y role and behavior: - `list` (default) — `role="list"`, items `role="listitem"`. Reorderable allowed. - `radiogroup` — `role="radiogroup"`, for a set of `nldd-list-item radio` rows: one choice, laid out as rows so each option can carry a count or a second line. The rows step out of the accessibility tree themselves (`role="none"`), so the radios are the group's own children. The arrows move focus here and activation checks, rather than the selection following focus as it does in `nldd-radio-button-group`. - `tree` — `role="tree"`, items `role="treeitem"`. Branch rows put their child rows in their own `slot="children"`, which the item renders as a `role="group"`. Level, position and set size are NOT authored: the nesting represents the hierarchy, so assistive technology derives them. A branch row must carry `expanded`; the group is hidden while it is false. Visual indentation is the consumer's — repeat a spacer-cell per level. Comes with its own keyboard, see "Tree" below. - `navigation` — host `role="navigation"`, items with `selected` get `aria-current="page"` on their inner `<a>` or `<button>`. - `form` — rows that are not actions themselves: the controls inside them are. A row of a label and a field, a switch, a menu button, or a value you cannot change at all. Semantically the same as `list` (`role="list"`, `role="listitem"`), and everything visual is unchanged; what falls away is the keyboard of a list you walk through. No arrow navigation, so no promise of it either, and no tab stop on the row: Tab goes straight to the controls, in source order, the way it does in any form. Rows that ARE actions (`href`, `button`, `checkbox`, or a segment) contradict that and warn in development. SwiftUI draws the same line between `List` and `Form`, for the same reason. - `listbox` — an accessible, filterable listbox (combobox pattern). The list renders its OWN search input (`role="combobox"`) pinned above the options; `.list__items` becomes `role="listbox"` and items become `role="option"`. Focus stays in the input, the active option moves via `aria-activedescendant`, and filtering is consumer-managed via the `input` event (toggle `[hidden]` on items). See "Listbox" below. Selection state is consumer-managed: the list never mutates `selected` itself. A list you walk through answers to the arrow keys, and there is no attribute to switch that on. Whether the keys do something is not a property of one list: it is what a reader may assume about all of them, and a per-list setting made that unknowable from the outside. It follows the type, which you can see before you touch a key. - ArrowUp / ArrowDown — move focus between the rows there is something to do with. A row of nothing but text is skipped, because focus that leads nowhere is a dead end. - Home / End — the first / last of those rows. - Tab — the list is ONE tab stop, so Tab moves past it rather than through it. Within the current row Tab walks that row's own controls: a chevron beside a checkbox, a menu button at the end. The same controls in the other rows are held out of the tab order (`tabindex="-1"`, or `no-tab` on a design-system control that keeps its tab stop in its own shadow root), and so are this row's once focus leaves the list, so tabbing back in lands on the row again. - Escape — out of a control the row holds, back onto the row. One level up, where Shift+Tab is one step back. On the row itself the list claims nothing, so Escape carries on to whatever holds the list, and a control showing a menu keeps the first press for closing that menu. While focus sits in a control a row holds, the list stands down: those keys are the control's, and a list that took them anyway would pull focus out of a combo box or a text field mid-word. What the row IS — its own link, button or segments — keeps answering here. Arrows move focus only; selection stays consumer-managed. Three types answer differently, and all three say so on screen before you touch a key: a listbox runs its keyboard from its search field, a reorderable list moves rows with the arrows, and a form has no rows to move between at all. In `type="listbox"` the list owns a native `<input role="combobox">` (mirroring how `nldd-combo-box` wires an input to a slotted listbox). Keyboard, handled on the input so focus never leaves it: - ArrowDown / ArrowUp — move the active option among the VISIBLE (non-`[hidden]`) options (wrap around). - Home / End — first / last visible option. - Enter — activate the active option by triggering its inner action (a link navigates, a button fires the consumer's handler). Selection stays consumer-managed. - Escape — clear the search value (and refire `input`). On every active change the input's `aria-activedescendant` is set to the active option's id and the option is scrolled into view. The active option (`_highlighted` on the item, a highlight) is distinct from `selected`. Filtering is the consumer's job: listen to `input` (`{ detail: { value } }`) and toggle `[hidden]` on items; after the visible set changes the list resets the active option to the first visible one. `reorderable` and the roving arrow keys are ignored in listbox mode (listbox has its own keyboard). A tree adds to that keyboard, and counts the rows of an open branch as part of the order the arrows walk: - ArrowRight — opens a closed branch; on an open one it steps to its first child. - ArrowLeft — closes an open branch; on a leaf it steps out to the parent row. - Enter — follows the row: its own link or button, or on a segmented branch the first action that is not the chevron. A branch with only a chevron folds instead. - Space — open and close, the same as Right and Left. Only while focus sits on the row itself: a row that is its own control, and a segmented action you tabbed into, handle both keys themselves. Opening and closing runs through the row's own disclosure control — the segment marked `disclosure`, or the row itself when it is a button. The list activates that control rather than writing `expanded`, so the state keeps being set in one place: the consumer's handler. A row that is a link is never activated this way, since that would navigate away. The tree is one tab stop. Focus lands on the row itself when the row has no control of its own, because that is where `treeitem` sits and it makes assistive technology announce the row rather than a button inside it. Tab then walks the controls of THAT row (a chevron beside a checkbox, say) and leaves the list after the last one. A deliberate deviation: strictly speaking a row with several controls is a `treegrid`, not a `tree`. We keep the tree semantics — level and set size are what matters here, not rows and columns — and borrow the "Tab within the row" behavior from the grid pattern. Should a tree with real columns come up, that is when `treegrid` earns its own type. On reorder (type="list" + reorderable), the list dispatches `nldd-reorder` with `fromIndex` / `toIndex` and expects the consumer to mutate the DOM (or their data model that renders the DOM). Focus is restored to the moved item's drag handle via a single `requestAnimationFrame` — this assumes the consumer reorders **synchronously** in the event handler. Async renderers (React, Vue, …) that update the DOM on a later tick will miss the focus restore and should manage focus themselves after their render commits. */
3678
3692
  'nldd-list': DefineComponent<NLDDListProps>;
3679
3693
  /** A row within an `nldd-list`. Renders as a link when `href` is set, as a checkbox when `checkbox` is set, as a button when `button` is set, or as a plain container otherwise. All cells and segments share one flat slot, in source order. Two rules govern every row: 1. State fills always paint the WIDENED row geometry — the row box extended by the indicator inline inset on both sides — whether or not the row is interactive. Paint never differs between a selected plain row and a selected interactive row. 2. The widened strip belongs to the ROW, never to a segment. A row with any action (its own `href`/`button`/`checkbox`, or a slotted segment) pulls itself outward (`is-interactive` host class → negative inline margin) and pads the row block back by the same amount, so content stays on the grid. A row-wide action owns that padding itself, making the whole widened box one hit area; slotted segments stay in the grid, so their footprint is position-independent and tree columns line up at any depth. By default the divider starts at the row's first text or title cell, so the line lands on the words rather than on whatever leads up to them — an icon, an avatar, a checkbox, or the spacers a tree indents with. Rows of different shapes then still line their dividers up with each other, and a tree's dividers step inward with its indentation. Text inside an `nldd-list-item-segment` counts as the row's content, and the marker is that text cell rather than the action: the action carries its own inline padding, so its edge sits before the words. A row with no text or title cell keeps the full content width. Mark a cell with `divider-start` and/or `divider-end` to place it yourself instead — an explicit marker replaces the derived one entirely, so `divider-start` on the leading cell restores the full-width line. Multiple markers resolve as the union: first `divider-start` through last `divider-end`. A start past the last end is an authoring error — the item DEV-warns and falls back to the full content width. A branch row can disclose its children in two ways: a dedicated `nldd-list-item-segment[disclosure]` segment (only the chevron is clickable), or the row itself as the control (`button` + `expanded`, the whole row toggles). In the second case, mark the chevron's `nldd-icon-cell` with `disclosure` and the row turns it with `expanded` — the same affordance, without having to trade a clickable row for a turning chevron. `checkbox` makes the WHOLE row the control: the inner action becomes a `role="checkbox"` button carrying `aria-checked`, it toggles `checked` on activation and fires `change`. Slot a visual `nldd-checkbox` (or any glyph) before the text and mark it `aria-hidden` + non-focusable — the row already conveys role and state, and a second focusable control would double the tab stops. Do NOT nest a real `<input type="checkbox">` in the action: interactive content inside a `<button>` is invalid HTML and AT announces the button, not the checked state. A `<label>` variant is not offered for the same reason it cannot work — label-to-input association walks the DOM tree, and a slotted input is not a descendant of a label in the shadow root. When it renders as a link, `target` and `rel` are forwarded to the inner `<a>` (e.g. `target="_blank" rel="noopener noreferrer"`). With `target="_blank"` the item also injects a visually hidden "opens in new tab" announcement for assistive technology (WCAG 2.1 SC 3.2.2). The item synchronizes its ARIA with its parent `nldd-list`'s `type`: - `list` parent → `role="listitem"` - `navigation` parent → `role="listitem"` + `aria-current="page"` on the inner `<a>` / `<button>` when `selected` - `listbox` parent → `role="option"` + `aria-selected` reflecting `selected`. The list points its search input's `aria-activedescendant` at the active option via `_highlighted` (separate from `selected`). */
3680
3694
  'nldd-list-item': DefineComponent<NLDDListItemProps>;
@@ -3705,7 +3719,7 @@ declare module 'vue' {
3705
3719
  'nldd-one-half-one-half-section': DefineComponent<NLDDOneHalfOneHalfSectionProps>;
3706
3720
  /** A section with a 1/3 sidebar on the left and 2/3 main content on the right. The columns wrap automatically when they become smaller than 280px. Padding and gap adjust via container queries. */
3707
3721
  'nldd-one-third-two-thirds-section': DefineComponent<NLDDOneThirdTwoThirdsSectionProps>;
3708
- /** A page layout with optional sticky header and footer. Without sticky-header, the host is the scroll container and the header is in normal flow. With sticky-header, the header becomes absolute and .page__scroll takes over scrolling. A ResizeObserver on the header sets padding-top on the scroll wrapper (only when not scrolled). In root-scroll mode (--context-scroll-mode: root, derived upstream by nldd-app-view) the page stops owning a scroller: the document scrolls and the sticky header/footer become position:sticky layers offset by --context-layer-top/bottom. The mode is read on connect/resize and reflected to [data-scroll] so the CSS can branch. */
3722
+ /** A page layout with optional sticky header and footer. Without sticky-header, the host is the scroll container and the header is in normal flow. With sticky-header, the header becomes absolute and .page__scroll takes over scrolling. A ResizeObserver on the header sets padding-top on the scroll wrapper (only when not scrolled). In root-scroll mode (--context-scroll-mode: root, derived upstream by nldd-app-view) the page stops owning a scroller: the document scrolls and the sticky header/footer stick against the document, offset by --context-inset-top/bottom. The mode is read on connect/resize and reflected to [data-scroll] so the CSS can branch. The page passes those insets on to its own content, with its sticky header and footer added: anything sticky inside (an nldd-sidebar-section, a sticky table head) reads --context-inset-top / --context-inset-bottom and clears every bar above and below it without being told a number. The heights are measured, because a top title bar shrinks as you scroll past its anchor. While the page owns the scroller, only its own bars count: the chrome above the page sits outside that scroller and does not push sticky content down. */
3709
3723
  'nldd-page': DefineComponent<NLDDPageProps>;
3710
3724
  /** The footer band at the bottom of a page. Hosts three optional rows in a fixed order: breadcrumbs (top), consumer-defined main content (middle), and a legal-bar (bottom). Dividers are drawn automatically between non-empty rows. Establishes its own container query (`page-footer-container`) so the responsive padding and gap react to the footer's own width, not the viewport. The host has `id="page-footer"` so a skip-link can target it directly. Use the sub-components `nldd-page-footer-legal-bar` and `nldd-page-footer-legal-bar-item` for the bottom row. */
3711
3725
  'nldd-page-footer': DefineComponent<NLDDPageFooterProps>;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The spacing scale, for the attributes that take a step of it.
3
+ *
4
+ * Spacing is rhythm: the point of a scale is that the space between things is
5
+ * the same handful of numbers on every page, so a value beside it is not a
6
+ * finer choice but a break in the pattern. These attributes take a step and
7
+ * nothing else, and this is the one place that turns a step into its token.
8
+ *
9
+ * Which also settles what the attribute means. `gap="16"` in a component that
10
+ * expected a CSS length wrote `--_gap: 16`, which is not one: the declaration
11
+ * fell away and the gap became zero with nothing said. Anything this cannot
12
+ * place is refused and named in dev instead, a length included — writing an
13
+ * unplaceable value is that same silent zero.
14
+ */
15
+ /** Every step there is. `'0'` is a value, not the absence of one. */
16
+ export declare const SPACING_SCALE: readonly ["0", "2", "4", "6", "8", "10", "12", "16", "20", "24", "28", "32", "40", "44", "48", "56", "64", "80", "96"];
17
+ export type SpacingSize = (typeof SPACING_SCALE)[number];
18
+ /**
19
+ * A step of the scale as the token it stands for.
20
+ *
21
+ * Returns null when there is nothing to set, so a caller can remove the
22
+ * property rather than write an empty one. `element` and `attribute` are only
23
+ * there to name the offender in a dev warning.
24
+ */
25
+ export declare function spacingToValue(value: string | undefined, element: string, attribute: string): string | null;
26
+ //# sourceMappingURL=spacing-scale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spacing-scale.d.ts","sourceRoot":"","sources":["../../src/utilities/spacing-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,qEAAqE;AACrE,eAAO,MAAM,aAAa,wHAGhB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAgBzD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GACf,MAAM,GAAG,IAAI,CAiBf"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The spacing scale, for the attributes that take a step of it.
3
+ *
4
+ * Spacing is rhythm: the point of a scale is that the space between things is
5
+ * the same handful of numbers on every page, so a value beside it is not a
6
+ * finer choice but a break in the pattern. These attributes take a step and
7
+ * nothing else, and this is the one place that turns a step into its token.
8
+ *
9
+ * Which also settles what the attribute means. `gap="16"` in a component that
10
+ * expected a CSS length wrote `--_gap: 16`, which is not one: the declaration
11
+ * fell away and the gap became zero with nothing said. Anything this cannot
12
+ * place is refused and named in dev instead, a length included — writing an
13
+ * unplaceable value is that same silent zero.
14
+ */
15
+ /** Every step there is. `'0'` is a value, not the absence of one. */
16
+ export const SPACING_SCALE = [
17
+ '0', '2', '4', '6', '8', '10', '12', '16', '20', '24',
18
+ '28', '32', '40', '44', '48', '56', '64', '80', '96',
19
+ ];
20
+ /** Anything that is not a bare number: a length, a percentage, a calc(). */
21
+ function looksLikeLength(value) {
22
+ return /[a-z%()]/i.test(value.trim());
23
+ }
24
+ const warned = new Set();
25
+ function warnOnce(element, attribute, message) {
26
+ const key = `${element}.${attribute}.${message}`;
27
+ if (warned.has(key))
28
+ return;
29
+ warned.add(key);
30
+ console.warn(`<${element}>: ${message}`);
31
+ }
32
+ /**
33
+ * A step of the scale as the token it stands for.
34
+ *
35
+ * Returns null when there is nothing to set, so a caller can remove the
36
+ * property rather than write an empty one. `element` and `attribute` are only
37
+ * there to name the offender in a dev warning.
38
+ */
39
+ export function spacingToValue(value, element, attribute) {
40
+ if (value === undefined || value === '')
41
+ return null;
42
+ const step = String(value).trim();
43
+ if (SPACING_SCALE.includes(step)) {
44
+ return step === '0' ? '0' : `var(--primitives-space-${step})`;
45
+ }
46
+ if (import.meta.env?.DEV) {
47
+ const why = looksLikeLength(step)
48
+ ? 'is a CSS length, and these attributes take a step of the spacing scale so the rhythm holds across the page'
49
+ : 'is not a step of the spacing scale';
50
+ warnOnce(element, attribute, `${attribute}="${step}" ${why} (${SPACING_SCALE.join(', ')}). Nothing is written, so the default stands.`);
51
+ }
52
+ return null;
53
+ }
54
+ //# sourceMappingURL=spacing-scale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spacing-scale.js","sourceRoot":"","sources":["../../src/utilities/spacing-scale.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IACrD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC3C,CAAC;AAIX,4EAA4E;AAC5E,SAAS,eAAe,CAAC,KAAa;IACrC,OAAO,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;AAEjC,SAAS,QAAQ,CAAC,OAAe,EAAE,SAAiB,EAAE,OAAe;IACpE,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;IACjD,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO;IAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,MAAM,OAAO,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC7B,KAAyB,EACzB,OAAe,EACf,SAAiB;IAEjB,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IAClC,IAAK,aAAmC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACzD,OAAO,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B,IAAI,GAAG,CAAC;IAC/D,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,eAAe,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,4GAA4G;YAC9G,CAAC,CAAC,oCAAoC,CAAC;QACxC,QAAQ,CACP,OAAO,EACP,SAAS,EACT,GAAG,SAAS,KAAK,IAAI,KAAK,GAAG,KAAK,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,+CAA+C,CACzG,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
@@ -4,8 +4,8 @@ type Constructor<T = LitElement> = new (...args: any[]) => T;
4
4
  * Adds `hide-below` and `hide-above` attributes that toggle visibility based
5
5
  * on the inline-size of an ancestor CSS container.
6
6
  *
7
- * Without a `containerName` argument the generated rule is an anonymous
8
- * `@container (…)` query — it matches the nearest ancestor that declares
7
+ * Without a `containerName` argument the rule is an anonymous `@container (…)`
8
+ * query — it matches the nearest ancestor that declares
9
9
  * `container-type: inline-size`. Pass a name to target a specific container
10
10
  * (e.g. `'cells-container'` for cells inside `nldd-list`, which sets that
11
11
  * name inline on its host as a Safari shadow-DOM workaround).
@@ -14,12 +14,15 @@ type Constructor<T = LitElement> = new (...args: any[]) => T;
14
14
  * (e.g. '320px', '20rem'). Named values resolve to the standard breakpoint
15
15
  * thresholds: `hide-below` uses the breakpoint's lower bound (e.g.
16
16
  * `hide-below="lg"` hides in sm+md and shows in lg), `hide-above` its upper
17
- * bound; the open edges (below sm, above lg) are no-ops. Container queries can't
18
- * read CSS variables in their conditions, so the query rule is generated at
19
- * runtime and injected as a <style> element in the component's shadow root,
20
- * wrapped in `:host { @container <name>? (…) { display: none !important; } }`
21
- * (nested form — the flattened `@container { :host { … } }` is unreliable in
22
- * Safari).
17
+ * bound; the open edges (below sm, above lg) are no-ops.
18
+ *
19
+ * The named values are static CSS (see `visibility-mixin.styles.ts`), added
20
+ * through `finalizeStyles` so that a component's own `static styles` does not
21
+ * have to know about them. A custom length has no static form: the threshold
22
+ * is only known at runtime and a container query cannot read one from a CSS
23
+ * variable, so its rule is written at runtime into a constructable stylesheet
24
+ * the shadow root adopts. Neither path is an inline stylesheet, so no consumer
25
+ * needs `'unsafe-inline'` in its `style-src` for either.
23
26
  *
24
27
  * @mixin VisibilityMixin
25
28
  *
@@ -1 +1 @@
1
- {"version":3,"file":"visibility-mixin.d.ts","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAuB,MAAM,KAAK,CAAC;AAGtD,KAAK,WAAW,CAAC,CAAC,GAAG,UAAU,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AA0C7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,eAAe,CAAC,KAAK,SAAS,WAAW,CAAC,UAAU,CAAC,EACpE,IAAI,EAAE,KAAK,EACX,aAAa,CAAC,EAAE,MAAM,GAgDc,KAAK,GACxC,WAAW,CAAC,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CACrE"}
1
+ {"version":3,"file":"visibility-mixin.d.ts","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAoE,MAAM,KAAK,CAAC;AAGnG,KAAK,WAAW,CAAC,CAAC,GAAG,UAAU,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAuC7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,eAAe,CAAC,KAAK,SAAS,WAAW,CAAC,UAAU,CAAC,EACpE,IAAI,EAAE,KAAK,EACX,aAAa,CAAC,EAAE,MAAM,GA0Ec,KAAK,GACxC,WAAW,CAAC,UAAU,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CACrE"}
@@ -5,37 +5,25 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { property } from 'lit/decorators.js';
8
- import { breakpoints } from '../assets/styles/breakpoints.js';
9
- // Resolve a hide-below/hide-above value to a container-query threshold. A named
10
- // breakpoint (sm/md/lg) maps to the standard boundary; the open edges (below
11
- // sm, above lg) are no-ops (null); any other value passes through as a length.
12
- function resolveHideBelow(value) {
13
- if (value === 'md')
14
- return breakpoints.smMax; // hidden in sm
15
- if (value === 'lg')
16
- return breakpoints.mdMax; // hidden in sm + md
17
- if (value === 'sm')
18
- return null; // nothing below sm
19
- return value;
20
- }
21
- function resolveHideAbove(value) {
22
- if (value === 'sm')
23
- return breakpoints.mdMin; // hidden in md + lg
24
- if (value === 'md')
25
- return breakpoints.lgMin; // hidden in lg
26
- if (value === 'lg')
27
- return null; // nothing above lg
8
+ import { visibilityStyles } from './visibility-mixin.styles.js';
9
+ const NAMED_BREAKPOINTS = new Set(['sm', 'md', 'lg']);
10
+ // A named breakpoint is already covered by the static stylesheet. Only a custom
11
+ // CSS length has to become a rule at runtime, because a container query cannot
12
+ // read its threshold from a variable.
13
+ function customThreshold(value) {
14
+ if (value === undefined || NAMED_BREAKPOINTS.has(value))
15
+ return null;
28
16
  return value;
29
17
  }
30
18
  /**
31
- * The open edges resolve to null, so the attribute is written but nothing ever
32
- * hides. That reads like a working value, and the name invites it: `hide-below`
19
+ * The open edges hide nothing, so the attribute is written but never applies.
20
+ * That reads like a working value, and the name invites it: `hide-below`
33
21
  * names the breakpoint you hide BELOW, so "hide it at sm" comes out as
34
22
  * `hide-below="md"` and `hide-below="sm"` does nothing at all. Say so once,
35
23
  * rather than let it look applied.
36
24
  */
37
- function warnNoOp(host, attribute, value, resolved, openEdge, edgeLabel) {
38
- if (value !== openEdge || resolved !== null)
25
+ function warnNoOp(host, attribute, value, openEdge, edgeLabel) {
26
+ if (value !== openEdge)
39
27
  return;
40
28
  console.warn(`[${host.localName}] ${attribute}="${openEdge}" never hides anything: there is no `
41
29
  + `breakpoint ${edgeLabel}. The value names the breakpoint you hide below, so the `
@@ -46,8 +34,8 @@ function warnNoOp(host, attribute, value, resolved, openEdge, edgeLabel) {
46
34
  * Adds `hide-below` and `hide-above` attributes that toggle visibility based
47
35
  * on the inline-size of an ancestor CSS container.
48
36
  *
49
- * Without a `containerName` argument the generated rule is an anonymous
50
- * `@container (…)` query — it matches the nearest ancestor that declares
37
+ * Without a `containerName` argument the rule is an anonymous `@container (…)`
38
+ * query — it matches the nearest ancestor that declares
51
39
  * `container-type: inline-size`. Pass a name to target a specific container
52
40
  * (e.g. `'cells-container'` for cells inside `nldd-list`, which sets that
53
41
  * name inline on its host as a Safari shadow-DOM workaround).
@@ -56,12 +44,15 @@ function warnNoOp(host, attribute, value, resolved, openEdge, edgeLabel) {
56
44
  * (e.g. '320px', '20rem'). Named values resolve to the standard breakpoint
57
45
  * thresholds: `hide-below` uses the breakpoint's lower bound (e.g.
58
46
  * `hide-below="lg"` hides in sm+md and shows in lg), `hide-above` its upper
59
- * bound; the open edges (below sm, above lg) are no-ops. Container queries can't
60
- * read CSS variables in their conditions, so the query rule is generated at
61
- * runtime and injected as a <style> element in the component's shadow root,
62
- * wrapped in `:host { @container <name>? (…) { display: none !important; } }`
63
- * (nested form — the flattened `@container { :host { … } }` is unreliable in
64
- * Safari).
47
+ * bound; the open edges (below sm, above lg) are no-ops.
48
+ *
49
+ * The named values are static CSS (see `visibility-mixin.styles.ts`), added
50
+ * through `finalizeStyles` so that a component's own `static styles` does not
51
+ * have to know about them. A custom length has no static form: the threshold
52
+ * is only known at runtime and a container query cannot read one from a CSS
53
+ * variable, so its rule is written at runtime into a constructable stylesheet
54
+ * the shadow root adopts. Neither path is an inline stylesheet, so no consumer
55
+ * needs `'unsafe-inline'` in its `style-src` for either.
65
56
  *
66
57
  * @mixin VisibilityMixin
67
58
  *
@@ -79,37 +70,59 @@ function warnNoOp(host, attribute, value, resolved, openEdge, edgeLabel) {
79
70
  */
80
71
  export function VisibilityMixin(Base, containerName) {
81
72
  class WithVisibility extends Base {
73
+ // Lit calls this from finalize() with whatever the most-derived class put
74
+ // in `static styles`, which is why the mixin can add its sheet here and a
75
+ // component's own `static styles =` never clobbers it.
76
+ //
77
+ // `Base` is the direct superclass, so this is `super.finalizeStyles` with
78
+ // the receiver kept; it is reached through the cast because a
79
+ // `Constructor<LitElement>` type parameter does not carry Lit's statics.
80
+ /** @internal */
81
+ static finalizeStyles(styles) {
82
+ const inherited = Base.finalizeStyles.call(this, styles);
83
+ return [...inherited, visibilityStyles(containerName)];
84
+ }
82
85
  updated(changed) {
83
86
  super.updated(changed);
84
87
  if (changed.has('hideBelow') || changed.has('hideAbove')) {
85
- this._updateVisibilityStyle();
88
+ this._updateVisibilityRules();
86
89
  }
87
90
  }
88
- _updateVisibilityStyle() {
89
- if (!this.shadowRoot)
91
+ // The rule for a custom length is built here, into a stylesheet the shadow
92
+ // root adopts rather than a <style> element written into it. A CSP judges
93
+ // the element and leaves the CSSOM alone, so this path needs no
94
+ // 'unsafe-inline' either.
95
+ _updateVisibilityRules() {
96
+ const root = this.shadowRoot;
97
+ if (!root)
90
98
  return;
91
99
  const containerPrefix = containerName ? `${containerName} ` : '';
92
100
  const rules = [];
93
- const below = this.hideBelow ? resolveHideBelow(this.hideBelow) : null;
94
- warnNoOp(this, 'hide-below', this.hideBelow, below, 'sm', 'below sm');
101
+ warnNoOp(this, 'hide-below', this.hideBelow, 'sm', 'below sm');
102
+ const below = customThreshold(this.hideBelow);
95
103
  if (below) {
96
104
  rules.push(`:host { @container ${containerPrefix}(max-width: ${below}) { display: none !important; } }`);
97
105
  }
98
- const above = this.hideAbove ? resolveHideAbove(this.hideAbove) : null;
99
- warnNoOp(this, 'hide-above', this.hideAbove, above, 'lg', 'above lg');
106
+ warnNoOp(this, 'hide-above', this.hideAbove, 'lg', 'above lg');
107
+ const above = customThreshold(this.hideAbove);
100
108
  if (above) {
101
109
  rules.push(`:host { @container ${containerPrefix}(min-width: ${above}) { display: none !important; } }`);
102
110
  }
103
111
  if (rules.length === 0) {
104
- this._visibilityStyle?.remove();
105
- this._visibilityStyle = undefined;
112
+ if (this._visibilitySheet) {
113
+ const dropped = this._visibilitySheet;
114
+ root.adoptedStyleSheets = Array.from(root.adoptedStyleSheets)
115
+ .filter((sheet) => sheet !== dropped);
116
+ this._visibilitySheet = undefined;
117
+ }
106
118
  return;
107
119
  }
108
- if (!this._visibilityStyle) {
109
- this._visibilityStyle = document.createElement('style');
110
- this.shadowRoot.appendChild(this._visibilityStyle);
120
+ if (!this._visibilitySheet) {
121
+ this._visibilitySheet = new CSSStyleSheet();
122
+ // Last, so it outranks the static sheet on a tie.
123
+ root.adoptedStyleSheets = [...root.adoptedStyleSheets, this._visibilitySheet];
111
124
  }
112
- this._visibilityStyle.textContent = rules.join('\n');
125
+ this._visibilitySheet.replaceSync(rules.join('\n'));
113
126
  }
114
127
  }
115
128
  __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"visibility-mixin.js","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"visibility-mixin.js","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type CSSResult } from 'lit';
2
+ /**
3
+ * The `@container` rules for the named `hide-below` / `hide-above` values.
4
+ *
5
+ * Static, so they reach the shadow root through `adoptedStyleSheets` instead
6
+ * of a `<style>` element. That keeps consumers on a `style-src` without
7
+ * `'unsafe-inline'`; a custom CSS length has no static form and gets its rule
8
+ * from the mixin at runtime, into an adopted sheet of its own.
9
+ *
10
+ * The rules are nested (`:host { @container … }`) rather than flattened, because
11
+ * `@container { :host { … } }` is unreliable in Safari.
12
+ */
13
+ export declare function visibilityStyles(containerName?: string): CSSResult;
14
+ //# sourceMappingURL=visibility-mixin.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visibility-mixin.styles.d.ts","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,KAAK,CAAC;AAYrD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CA+BlE"}
@@ -0,0 +1,52 @@
1
+ import { css, unsafeCSS } from 'lit';
2
+ import { breakpoints } from '../assets/styles/breakpoints.js';
3
+ const smMax = unsafeCSS(breakpoints.smMax);
4
+ const mdMin = unsafeCSS(breakpoints.mdMin);
5
+ const mdMax = unsafeCSS(breakpoints.mdMax);
6
+ const lgMin = unsafeCSS(breakpoints.lgMin);
7
+ // One sheet per container name, so every component passing the same name
8
+ // shares a single constructable stylesheet instead of each adopting its own.
9
+ const sheets = new Map();
10
+ /**
11
+ * The `@container` rules for the named `hide-below` / `hide-above` values.
12
+ *
13
+ * Static, so they reach the shadow root through `adoptedStyleSheets` instead
14
+ * of a `<style>` element. That keeps consumers on a `style-src` without
15
+ * `'unsafe-inline'`; a custom CSS length has no static form and gets its rule
16
+ * from the mixin at runtime, into an adopted sheet of its own.
17
+ *
18
+ * The rules are nested (`:host { @container … }`) rather than flattened, because
19
+ * `@container { :host { … } }` is unreliable in Safari.
20
+ */
21
+ export function visibilityStyles(containerName) {
22
+ const key = containerName ?? '';
23
+ const cached = sheets.get(key);
24
+ if (cached)
25
+ return cached;
26
+ const container = unsafeCSS(containerName ? `${containerName} ` : '');
27
+ const sheet = css `
28
+ /* # Hide below: the value names the breakpoint you hide BELOW */
29
+
30
+ :host([hide-below="md"]) {
31
+ @container ${container}(max-width: ${smMax}) { display: none !important; }
32
+ }
33
+
34
+ :host([hide-below="lg"]) {
35
+ @container ${container}(max-width: ${mdMax}) { display: none !important; }
36
+ }
37
+
38
+
39
+ /* # Hide above */
40
+
41
+ :host([hide-above="sm"]) {
42
+ @container ${container}(min-width: ${mdMin}) { display: none !important; }
43
+ }
44
+
45
+ :host([hide-above="md"]) {
46
+ @container ${container}(min-width: ${lgMin}) { display: none !important; }
47
+ }
48
+ `;
49
+ sheets.set(key, sheet);
50
+ return sheet;
51
+ }
52
+ //# sourceMappingURL=visibility-mixin.styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visibility-mixin.styles.js","sourceRoot":"","sources":["../../src/utilities/visibility-mixin.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,SAAS,EAAkB,MAAM,KAAK,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AAE3C,yEAAyE;AACzE,6EAA6E;AAC7E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,aAAsB;IACtD,MAAM,GAAG,GAAG,aAAa,IAAI,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,SAAS,GAAG,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtE,MAAM,KAAK,GAAG,GAAG,CAAA;;;;gBAIF,SAAS,eAAe,KAAK;;;;gBAI7B,SAAS,eAAe,KAAK;;;;;;;gBAO7B,SAAS,eAAe,KAAK;;;;gBAI7B,SAAS,eAAe,KAAK;;EAE3C,CAAC;IAEF,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACvB,OAAO,KAAK,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nldd/design-system",
3
- "version": "0.8.85",
3
+ "version": "0.8.86",
4
4
  "description": "Design System voor Nederlandse Digitale Dienst",
5
5
  "type": "module",
6
6
  "main": "dist/components/components.js",
@@ -455,6 +455,8 @@
455
455
  "./styles/variables": "./dist/css/variables.css",
456
456
  "./styles/tokens": "./dist/css/tokens.css",
457
457
  "./styles/fouc": "./dist/css/fouc.css",
458
+ "./favicon.svg": "./dist/favicon.svg",
459
+ "./touch-icon.png": "./dist/touch-icon.png",
458
460
  "./breakpoints": {
459
461
  "types": "./dist/assets/styles/breakpoints.d.ts",
460
462
  "default": "./dist/assets/styles/breakpoints.js"
@@ -478,8 +480,9 @@
478
480
  "registry": "https://registry.npmjs.org"
479
481
  },
480
482
  "scripts": {
481
- "build": "npm run build:styles && npm run validate:styles && npm run validate:host-styles && npm run build:components",
483
+ "build": "npm run build:styles && npm run build:assets && npm run validate:styles && npm run validate:host-styles && npm run build:components",
482
484
  "build:styles": "rm -rf dist/css dist/fonts && mkdir -p dist/css dist/fonts && cp src/assets/styles/variables.css src/assets/styles/colors.generated.css src/assets/styles/rijksoverheid-fonts.css src/assets/styles/document-reset.css src/assets/styles/fouc.css dist/css/ && cp src/components/content/rich-text/rich-text.css src/components/forms/form/form.css src/components/forms/form-section/form-section.css dist/css/ && printf '@import \"./rijksoverheid-fonts.css\";\\n@import \"./variables.css\";\\n@import \"./document-reset.css\";\\n@import \"./rich-text.css\";\\n@import \"./form-section.css\";\\n@import \"./form.css\";\\n@import \"./fouc.css\";\\n' > dist/css/global.css && printf '@import \"./variables.css\";\\n@import \"./document-reset.css\";\\n@import \"./rich-text.css\";\\n@import \"./form-section.css\";\\n@import \"./form.css\";\\n@import \"./fouc.css\";\\n' > dist/css/global-system-font.css && printf '@import \"./rijksoverheid-fonts.css\";\\n@import \"./variables.css\";\\n' > dist/css/tokens.css && cp src/assets/fonts/*.woff2 dist/fonts/",
485
+ "build:assets": "mkdir -p dist && cp src/assets/favicon/favicon.svg src/assets/favicon/touch-icon.png dist/",
483
486
  "generate:colors": "node scripts/generate-colors.js",
484
487
  "generate:component-reference": "node scripts/generate-component-reference.js",
485
488
  "generate:cem": "cem analyze && npm run generate:vue-types",