ngwr 12.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/README.md +79 -20
  2. package/fesm2022/ngwr-action-sheet.mjs +3 -3
  3. package/fesm2022/ngwr-affix.mjs +3 -3
  4. package/fesm2022/ngwr-alert.mjs +3 -3
  5. package/fesm2022/ngwr-anchor.mjs +3 -3
  6. package/fesm2022/ngwr-aurora.mjs +3 -3
  7. package/fesm2022/ngwr-avatar.mjs +3 -3
  8. package/fesm2022/ngwr-back-top.mjs +3 -3
  9. package/fesm2022/ngwr-badge.mjs +6 -6
  10. package/fesm2022/ngwr-bar-chart.mjs +3 -3
  11. package/fesm2022/ngwr-blur-text.mjs +3 -3
  12. package/fesm2022/ngwr-border-glow.mjs +3 -3
  13. package/fesm2022/ngwr-breadcrumbs.mjs +6 -6
  14. package/fesm2022/ngwr-burger.mjs +3 -3
  15. package/fesm2022/ngwr-button.mjs +6 -6
  16. package/fesm2022/ngwr-calendar-heatmap.mjs +3 -3
  17. package/fesm2022/ngwr-calendar.mjs +3 -3
  18. package/fesm2022/ngwr-card.mjs +9 -9
  19. package/fesm2022/ngwr-carousel.mjs +6 -6
  20. package/fesm2022/ngwr-cascader.mjs +3 -3
  21. package/fesm2022/ngwr-checkbox.mjs +6 -6
  22. package/fesm2022/ngwr-circular-text.mjs +3 -3
  23. package/fesm2022/ngwr-click-spark.mjs +3 -3
  24. package/fesm2022/ngwr-clipboard.mjs +3 -3
  25. package/fesm2022/ngwr-collapse.mjs +9 -9
  26. package/fesm2022/ngwr-color-picker.mjs +6 -6
  27. package/fesm2022/ngwr-color-picker.mjs.map +1 -1
  28. package/fesm2022/ngwr-command-palette.mjs +3 -3
  29. package/fesm2022/ngwr-compare.mjs +3 -3
  30. package/fesm2022/ngwr-confetti.mjs +3 -3
  31. package/fesm2022/ngwr-context-menu.mjs +12 -12
  32. package/fesm2022/ngwr-cookie.mjs +3 -3
  33. package/fesm2022/ngwr-counter.mjs +6 -6
  34. package/fesm2022/ngwr-date-adapters-fns.mjs +3 -3
  35. package/fesm2022/ngwr-date-adapters-luxon.mjs +3 -3
  36. package/fesm2022/ngwr-date-picker.mjs +18 -18
  37. package/fesm2022/ngwr-date.mjs +3 -3
  38. package/fesm2022/ngwr-decrypt-text.mjs +3 -3
  39. package/fesm2022/ngwr-density.mjs +6 -6
  40. package/fesm2022/ngwr-descriptions.mjs +6 -6
  41. package/fesm2022/ngwr-dialog.mjs +15 -15
  42. package/fesm2022/ngwr-directives.mjs +12 -12
  43. package/fesm2022/ngwr-divider.mjs +3 -3
  44. package/fesm2022/ngwr-donut-chart.mjs +3 -3
  45. package/fesm2022/ngwr-drag-drop.mjs +6 -6
  46. package/fesm2022/ngwr-drawer.mjs +18 -18
  47. package/fesm2022/ngwr-dropdown.mjs +9 -9
  48. package/fesm2022/ngwr-empty.mjs +3 -3
  49. package/fesm2022/ngwr-event-calendar.mjs +6 -6
  50. package/fesm2022/ngwr-falling-text.mjs +3 -3
  51. package/fesm2022/ngwr-file-upload.mjs +3 -3
  52. package/fesm2022/ngwr-form.mjs +9 -9
  53. package/fesm2022/ngwr-fuzzy-text.mjs +3 -3
  54. package/fesm2022/ngwr-gauge.mjs +3 -3
  55. package/fesm2022/ngwr-glitch-text.mjs +3 -3
  56. package/fesm2022/ngwr-gradient-text.mjs +3 -3
  57. package/fesm2022/ngwr-hotkey.mjs +6 -6
  58. package/fesm2022/ngwr-i18n.mjs +9 -9
  59. package/fesm2022/ngwr-icon.mjs +6 -6
  60. package/fesm2022/ngwr-image-cropper.mjs +3 -3
  61. package/fesm2022/ngwr-input-number.mjs +3 -3
  62. package/fesm2022/ngwr-input-otp.mjs +3 -3
  63. package/fesm2022/ngwr-input.mjs +15 -15
  64. package/fesm2022/ngwr-keyboard.mjs +3 -3
  65. package/fesm2022/ngwr-knob.mjs +3 -3
  66. package/fesm2022/ngwr-layout.mjs +15 -15
  67. package/fesm2022/ngwr-lightbox.mjs +3 -3
  68. package/fesm2022/ngwr-line-chart.mjs +3 -3
  69. package/fesm2022/ngwr-list.mjs +6 -6
  70. package/fesm2022/ngwr-loading-bar.mjs +6 -6
  71. package/fesm2022/ngwr-markdown.mjs +6 -6
  72. package/fesm2022/ngwr-marquee.mjs +3 -3
  73. package/fesm2022/ngwr-media.mjs +3 -3
  74. package/fesm2022/ngwr-mention.mjs +6 -6
  75. package/fesm2022/ngwr-meta.mjs +6 -6
  76. package/fesm2022/ngwr-meter-group.mjs +3 -3
  77. package/fesm2022/ngwr-overlay.mjs +6 -6
  78. package/fesm2022/ngwr-page-header.mjs +3 -3
  79. package/fesm2022/ngwr-pagination.mjs +72 -9
  80. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  81. package/fesm2022/ngwr-pipes.mjs +21 -21
  82. package/fesm2022/ngwr-platform.mjs +9 -9
  83. package/fesm2022/ngwr-popconfirm.mjs +6 -6
  84. package/fesm2022/ngwr-popover.mjs +6 -6
  85. package/fesm2022/ngwr-progress.mjs +3 -3
  86. package/fesm2022/ngwr-pull-to-refresh.mjs +3 -3
  87. package/fesm2022/ngwr-qr.mjs +3 -3
  88. package/fesm2022/ngwr-radio.mjs +6 -6
  89. package/fesm2022/ngwr-rating.mjs +3 -3
  90. package/fesm2022/ngwr-result.mjs +12 -12
  91. package/fesm2022/ngwr-rotating-text.mjs +3 -3
  92. package/fesm2022/ngwr-scroll.mjs +3 -3
  93. package/fesm2022/ngwr-segmented-testing.mjs +71 -0
  94. package/fesm2022/ngwr-segmented-testing.mjs.map +1 -1
  95. package/fesm2022/ngwr-segmented.mjs +98 -8
  96. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  97. package/fesm2022/ngwr-select.mjs +9 -9
  98. package/fesm2022/ngwr-shiny-text.mjs +6 -6
  99. package/fesm2022/ngwr-sidebar.mjs +3 -3
  100. package/fesm2022/ngwr-skeleton.mjs +3 -3
  101. package/fesm2022/ngwr-slider.mjs +3 -3
  102. package/fesm2022/ngwr-sparkline.mjs +3 -3
  103. package/fesm2022/ngwr-speed-dial.mjs +3 -3
  104. package/fesm2022/ngwr-spinner.mjs +3 -3
  105. package/fesm2022/ngwr-splash-cursor.mjs +3 -3
  106. package/fesm2022/ngwr-split-text.mjs +3 -3
  107. package/fesm2022/ngwr-splitter.mjs +3 -3
  108. package/fesm2022/ngwr-spotlight-card.mjs +6 -6
  109. package/fesm2022/ngwr-squircle.mjs +6 -6
  110. package/fesm2022/ngwr-star-border.mjs +3 -3
  111. package/fesm2022/ngwr-statistic.mjs +9 -9
  112. package/fesm2022/ngwr-stepper.mjs +6 -6
  113. package/fesm2022/ngwr-storage.mjs +3 -3
  114. package/fesm2022/ngwr-switch.mjs +3 -3
  115. package/fesm2022/ngwr-table.mjs +18 -18
  116. package/fesm2022/ngwr-tabs.mjs +6 -6
  117. package/fesm2022/ngwr-textarea.mjs +3 -3
  118. package/fesm2022/ngwr-theme.mjs +3 -3
  119. package/fesm2022/ngwr-tilt-card.mjs +6 -6
  120. package/fesm2022/ngwr-timeline.mjs +6 -6
  121. package/fesm2022/ngwr-toast.mjs +9 -9
  122. package/fesm2022/ngwr-toolbar.mjs +3 -3
  123. package/fesm2022/ngwr-tour.mjs +6 -6
  124. package/fesm2022/ngwr-transfer.mjs +3 -3
  125. package/fesm2022/ngwr-tree.mjs +3 -3
  126. package/fesm2022/ngwr-typewriter.mjs +3 -3
  127. package/fesm2022/ngwr-typography.mjs +3 -3
  128. package/fesm2022/ngwr-version.mjs +1 -1
  129. package/fesm2022/ngwr-version.mjs.map +1 -1
  130. package/fesm2022/ngwr-virtual-scroll.mjs +3 -3
  131. package/fesm2022/ngwr-waves.mjs +3 -3
  132. package/fesm2022/ngwr-window.mjs +12 -12
  133. package/llms-full.txt +1 -1
  134. package/llms.txt +24 -2
  135. package/package.json +1 -1
  136. package/types/ngwr-pagination.d.ts +11 -0
  137. package/types/ngwr-segmented-testing.d.ts +44 -0
  138. package/types/ngwr-segmented.d.ts +86 -4
  139. package/types/ngwr-version.d.ts +1 -1
@@ -572,10 +572,10 @@ class WrWindow {
572
572
  this.x_.set(clamp(this.x_(), MIN_ON_VIEWPORT - w, vw - MIN_ON_VIEWPORT));
573
573
  this.y_.set(clamp(this.y_(), 0, vh - MIN_ON_VIEWPORT));
574
574
  }
575
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindow, deps: [], target: i0.ɵɵFactoryTarget.Component });
576
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrWindow, isStandalone: true, selector: "wr-window", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, initialX: { classPropertyName: "initialX", publicName: "initialX", isSignal: true, isRequired: false, transformFunction: null }, initialY: { classPropertyName: "initialY", publicName: "initialY", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, initialWidth: { classPropertyName: "initialWidth", publicName: "initialWidth", isSignal: true, isRequired: false, transformFunction: null }, initialHeight: { classPropertyName: "initialHeight", publicName: "initialHeight", isSignal: true, isRequired: false, transformFunction: null }, os: { classPropertyName: "os", publicName: "os", isSignal: true, isRequired: false, transformFunction: null }, chromeSize: { classPropertyName: "chromeSize", publicName: "chromeSize", isSignal: true, isRequired: false, transformFunction: null }, animations: { classPropertyName: "animations", publicName: "animations", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, movable: { classPropertyName: "movable", publicName: "movable", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, keepInViewport: { classPropertyName: "keepInViewport", publicName: "keepInViewport", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, dragHandle: { classPropertyName: "dragHandle", publicName: "dragHandle", isSignal: true, isRequired: false, transformFunction: null }, showMinimize: { classPropertyName: "showMinimize", publicName: "showMinimize", isSignal: true, isRequired: false, transformFunction: null }, showMaximize: { classPropertyName: "showMaximize", publicName: "showMaximize", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", state: "stateChange", closed: "closed", moved: "moved", resized: "resized" }, host: { attributes: { "role": "dialog" }, listeners: { "pointerdown": "focusWindow()" }, properties: { "class": "classes()", "style.left.px": "x()", "style.top.px": "y()", "style.width.px": "width()", "style.height.px": "height()", "style.z-index": "z()", "attr.aria-hidden": "!open()", "attr.aria-labelledby": "titleId" } }, ngImport: i0, template: "<!--\n The double-click gate is `!== false`, NOT `maximizeVisible()`, and the\n difference is a window nobody can get out of. The Linux preset hides the\n maximize BUTTON; the gesture is how GNOME maximizes, and it worked on every\n chrome before this input went tri-state. Gating it on button visibility would\n have killed it there \u2014 and `maximized` is reachable on Linux with no button at\n all (a snap to the top edge, `ref.maximize()`, a restored layout), after which\n every exit disappears at once: no restore-down button, no minimize button,\n `startMove` refuses while the state is not `normal`, the resize handles are not\n rendered, and the only key the window listens for is Escape, which closes it.\n An explicit `showMaximize: false` still turns the gesture off everywhere.\n-->\n<div class=\"wr-window__chrome\" (pointerdown)=\"startMove($event)\" (dblclick)=\"showMaximize() !== false && maximize()\">\n <div class=\"wr-window__title\" [attr.id]=\"titleId\">{{ title() }}</div>\n <div class=\"wr-window__title-extra\">\n <ng-content select=\"[wrWindowTitleExtra]\" />\n </div>\n\n <div class=\"wr-window__chrome-actions\">\n @if (resolvedOs() === 'macos') {\n <!-- macOS-style traffic-light cluster: close \u2192 minimize \u2192 maximize.\n Glyphs (\u00D7, \u2212, +) appear on cluster hover. -->\n @if (showClose()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path\n d=\"M2.2 2.2 L7.8 7.8 M7.8 2.2 L2.2 7.8\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n @if (minimizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--minimize\"\n [attr.aria-label]=\"minimizeActionLabel()\"\n (click)=\"minimize()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <line x1=\"2\" y1=\"5\" x2=\"8\" y2=\"5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n @if (maximizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--maximize\"\n [attr.aria-label]=\"maximizeActionLabel()\"\n (click)=\"maximize()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n @if (state() === 'maximized') {\n <path\n d=\"M3 1 L1 1 L1 3 M7 1 L9 1 L9 3 M1 7 L1 9 L3 9 M9 7 L9 9 L7 9\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n fill=\"none\"\n />\n } @else {\n <path d=\"M2 5 L8 5 M5 2 L5 8\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n }\n </svg>\n </button>\n }\n } @else {\n <!-- Windows / Linux glyph buttons. Linux hides minimize and maximize by\n DEFAULT, not by rule: `minimizeVisible()` resolves the input first, so\n `[showMinimize]=\"true\"` puts the button back \u2014 which is the only way a\n user on Linux can reach `<wr-window-taskbar>` at all. -->\n @if (minimizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--minimize\"\n [attr.aria-label]=\"minimizeActionLabel()\"\n (click)=\"minimize()\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <line x1=\"1\" y1=\"8\" x2=\"9\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n\n @if (maximizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--maximize\"\n [attr.aria-label]=\"maximizeActionLabel()\"\n (click)=\"maximize()\"\n >\n @if (state() === 'maximized') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"6\" height=\"6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <rect x=\"3\" y=\"1\" width=\"6\" height=\"6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n </svg>\n } @else {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <rect x=\"1\" y=\"1\" width=\"8\" height=\"8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n </svg>\n }\n </button>\n }\n\n @if (showClose()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M1 1 L9 9 M9 1 L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n }\n </div>\n</div>\n\n<div class=\"wr-window__body\">\n <ng-content />\n</div>\n\n<div class=\"wr-window__status-bar\">\n <ng-content select=\"[wrWindowStatusBar]\" />\n</div>\n\n@if (resizable() && state() === 'normal') {\n <span class=\"wr-window__handle wr-window__handle--t\" (pointerdown)=\"resizeT($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--r\" (pointerdown)=\"resizeR($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--b\" (pointerdown)=\"resizeB($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--l\" (pointerdown)=\"resizeL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--tl\" (pointerdown)=\"resizeTL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--tr\" (pointerdown)=\"resizeTR($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--bl\" (pointerdown)=\"resizeBL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--br\" (pointerdown)=\"resizeBR($event)\"></span>\n}\n", encapsulation: i0.ViewEncapsulation.None });
575
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindow, deps: [], target: i0.ɵɵFactoryTarget.Component });
576
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrWindow, isStandalone: true, selector: "wr-window", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, initialX: { classPropertyName: "initialX", publicName: "initialX", isSignal: true, isRequired: false, transformFunction: null }, initialY: { classPropertyName: "initialY", publicName: "initialY", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, initialWidth: { classPropertyName: "initialWidth", publicName: "initialWidth", isSignal: true, isRequired: false, transformFunction: null }, initialHeight: { classPropertyName: "initialHeight", publicName: "initialHeight", isSignal: true, isRequired: false, transformFunction: null }, os: { classPropertyName: "os", publicName: "os", isSignal: true, isRequired: false, transformFunction: null }, chromeSize: { classPropertyName: "chromeSize", publicName: "chromeSize", isSignal: true, isRequired: false, transformFunction: null }, animations: { classPropertyName: "animations", publicName: "animations", isSignal: true, isRequired: false, transformFunction: null }, minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, maxWidth: { classPropertyName: "maxWidth", publicName: "maxWidth", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, movable: { classPropertyName: "movable", publicName: "movable", isSignal: true, isRequired: false, transformFunction: null }, resizable: { classPropertyName: "resizable", publicName: "resizable", isSignal: true, isRequired: false, transformFunction: null }, keepInViewport: { classPropertyName: "keepInViewport", publicName: "keepInViewport", isSignal: true, isRequired: false, transformFunction: null }, snap: { classPropertyName: "snap", publicName: "snap", isSignal: true, isRequired: false, transformFunction: null }, dragHandle: { classPropertyName: "dragHandle", publicName: "dragHandle", isSignal: true, isRequired: false, transformFunction: null }, showMinimize: { classPropertyName: "showMinimize", publicName: "showMinimize", isSignal: true, isRequired: false, transformFunction: null }, showMaximize: { classPropertyName: "showMaximize", publicName: "showMaximize", isSignal: true, isRequired: false, transformFunction: null }, showClose: { classPropertyName: "showClose", publicName: "showClose", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange", state: "stateChange", closed: "closed", moved: "moved", resized: "resized" }, host: { attributes: { "role": "dialog" }, listeners: { "pointerdown": "focusWindow()" }, properties: { "class": "classes()", "style.left.px": "x()", "style.top.px": "y()", "style.width.px": "width()", "style.height.px": "height()", "style.z-index": "z()", "attr.aria-hidden": "!open()", "attr.aria-labelledby": "titleId" } }, ngImport: i0, template: "<!--\n The double-click gate is `!== false`, NOT `maximizeVisible()`, and the\n difference is a window nobody can get out of. The Linux preset hides the\n maximize BUTTON; the gesture is how GNOME maximizes, and it worked on every\n chrome before this input went tri-state. Gating it on button visibility would\n have killed it there \u2014 and `maximized` is reachable on Linux with no button at\n all (a snap to the top edge, `ref.maximize()`, a restored layout), after which\n every exit disappears at once: no restore-down button, no minimize button,\n `startMove` refuses while the state is not `normal`, the resize handles are not\n rendered, and the only key the window listens for is Escape, which closes it.\n An explicit `showMaximize: false` still turns the gesture off everywhere.\n-->\n<div class=\"wr-window__chrome\" (pointerdown)=\"startMove($event)\" (dblclick)=\"showMaximize() !== false && maximize()\">\n <div class=\"wr-window__title\" [attr.id]=\"titleId\">{{ title() }}</div>\n <div class=\"wr-window__title-extra\">\n <ng-content select=\"[wrWindowTitleExtra]\" />\n </div>\n\n <div class=\"wr-window__chrome-actions\">\n @if (resolvedOs() === 'macos') {\n <!-- macOS-style traffic-light cluster: close \u2192 minimize \u2192 maximize.\n Glyphs (\u00D7, \u2212, +) appear on cluster hover. -->\n @if (showClose()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path\n d=\"M2.2 2.2 L7.8 7.8 M7.8 2.2 L2.2 7.8\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n }\n @if (minimizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--minimize\"\n [attr.aria-label]=\"minimizeActionLabel()\"\n (click)=\"minimize()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <line x1=\"2\" y1=\"5\" x2=\"8\" y2=\"5\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n @if (maximizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--maximize\"\n [attr.aria-label]=\"maximizeActionLabel()\"\n (click)=\"maximize()\"\n >\n <svg class=\"wr-window__chrome-action-glyph\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n @if (state() === 'maximized') {\n <path\n d=\"M3 1 L1 1 L1 3 M7 1 L9 1 L9 3 M1 7 L1 9 L3 9 M9 7 L9 9 L7 9\"\n stroke=\"currentColor\"\n stroke-width=\"1.4\"\n stroke-linecap=\"round\"\n fill=\"none\"\n />\n } @else {\n <path d=\"M2 5 L8 5 M5 2 L5 8\" stroke=\"currentColor\" stroke-width=\"1.4\" stroke-linecap=\"round\" />\n }\n </svg>\n </button>\n }\n } @else {\n <!-- Windows / Linux glyph buttons. Linux hides minimize and maximize by\n DEFAULT, not by rule: `minimizeVisible()` resolves the input first, so\n `[showMinimize]=\"true\"` puts the button back \u2014 which is the only way a\n user on Linux can reach `<wr-window-taskbar>` at all. -->\n @if (minimizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--minimize\"\n [attr.aria-label]=\"minimizeActionLabel()\"\n (click)=\"minimize()\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <line x1=\"1\" y1=\"8\" x2=\"9\" y2=\"8\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n\n @if (maximizeVisible()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--maximize\"\n [attr.aria-label]=\"maximizeActionLabel()\"\n (click)=\"maximize()\"\n >\n @if (state() === 'maximized') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <rect x=\"1.5\" y=\"2.5\" width=\"6\" height=\"6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n <rect x=\"3\" y=\"1\" width=\"6\" height=\"6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n </svg>\n } @else {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <rect x=\"1\" y=\"1\" width=\"8\" height=\"8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.2\" />\n </svg>\n }\n </button>\n }\n\n @if (showClose()) {\n <button\n type=\"button\"\n class=\"wr-window__chrome-action wr-window__chrome-action--close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M1 1 L9 9 M9 1 L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n }\n }\n </div>\n</div>\n\n<div class=\"wr-window__body\">\n <ng-content />\n</div>\n\n<div class=\"wr-window__status-bar\">\n <ng-content select=\"[wrWindowStatusBar]\" />\n</div>\n\n@if (resizable() && state() === 'normal') {\n <span class=\"wr-window__handle wr-window__handle--t\" (pointerdown)=\"resizeT($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--r\" (pointerdown)=\"resizeR($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--b\" (pointerdown)=\"resizeB($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--l\" (pointerdown)=\"resizeL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--tl\" (pointerdown)=\"resizeTL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--tr\" (pointerdown)=\"resizeTR($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--bl\" (pointerdown)=\"resizeBL($event)\"></span>\n <span class=\"wr-window__handle wr-window__handle--br\" (pointerdown)=\"resizeBR($event)\"></span>\n}\n", encapsulation: i0.ViewEncapsulation.None });
577
577
  }
578
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindow, decorators: [{
578
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindow, decorators: [{
579
579
  type: Component,
580
580
  args: [{ selector: 'wr-window', encapsulation: ViewEncapsulation.None, host: {
581
581
  role: 'dialog',
@@ -746,10 +746,10 @@ class WrWindowContainer {
746
746
  });
747
747
  });
748
748
  }
749
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowContainer, deps: [], target: i0.ɵɵFactoryTarget.Component });
750
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrWindowContainer, isStandalone: true, selector: "wr-window-container", viewQueries: [{ propertyName: "contentVcr", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "wrWindow", first: true, predicate: WrWindow, descendants: true, isSignal: true }], ngImport: i0, template: "<wr-window\n [open]=\"true\"\n [title]=\"ref.title()\"\n [os]=\"config.os ?? 'auto'\"\n [size]=\"config.size ?? 'md'\"\n [chromeSize]=\"config.chromeSize ?? 'normal'\"\n [animations]=\"config.animations ?? true\"\n [initialX]=\"config.x ?? null\"\n [initialY]=\"config.y ?? null\"\n [initialWidth]=\"config.width ?? null\"\n [initialHeight]=\"config.height ?? null\"\n [minWidth]=\"config.minWidth ?? 220\"\n [minHeight]=\"config.minHeight ?? 140\"\n [maxWidth]=\"config.maxWidth ?? 1000000\"\n [maxHeight]=\"config.maxHeight ?? 1000000\"\n [movable]=\"config.movable ?? true\"\n [resizable]=\"config.resizable ?? true\"\n [keepInViewport]=\"config.keepInViewport ?? true\"\n [snap]=\"config.snap ?? 'none'\"\n [dragHandle]=\"config.dragHandle ?? null\"\n [showMinimize]=\"config.showMinimize ?? null\"\n [showMaximize]=\"config.showMaximize ?? null\"\n [showClose]=\"config.showClose ?? true\"\n (closed)=\"ref.close()\"\n #window\n>\n <ng-container #content />\n</wr-window>\n\n@if (window.snapTarget(); as target) {\n <div class=\"wr-window__snap-hint\" [attr.data-target]=\"target\" aria-hidden=\"true\"></div>\n}\n", dependencies: [{ kind: "component", type: WrWindow, selector: "wr-window", inputs: ["open", "state", "title", "initialX", "initialY", "size", "initialWidth", "initialHeight", "os", "chromeSize", "animations", "minWidth", "minHeight", "maxWidth", "maxHeight", "movable", "resizable", "keepInViewport", "snap", "dragHandle", "showMinimize", "showMaximize", "showClose"], outputs: ["openChange", "stateChange", "closed", "moved", "resized"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
749
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowContainer, deps: [], target: i0.ɵɵFactoryTarget.Component });
750
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrWindowContainer, isStandalone: true, selector: "wr-window-container", viewQueries: [{ propertyName: "contentVcr", first: true, predicate: ["content"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "wrWindow", first: true, predicate: WrWindow, descendants: true, isSignal: true }], ngImport: i0, template: "<wr-window\n [open]=\"true\"\n [title]=\"ref.title()\"\n [os]=\"config.os ?? 'auto'\"\n [size]=\"config.size ?? 'md'\"\n [chromeSize]=\"config.chromeSize ?? 'normal'\"\n [animations]=\"config.animations ?? true\"\n [initialX]=\"config.x ?? null\"\n [initialY]=\"config.y ?? null\"\n [initialWidth]=\"config.width ?? null\"\n [initialHeight]=\"config.height ?? null\"\n [minWidth]=\"config.minWidth ?? 220\"\n [minHeight]=\"config.minHeight ?? 140\"\n [maxWidth]=\"config.maxWidth ?? 1000000\"\n [maxHeight]=\"config.maxHeight ?? 1000000\"\n [movable]=\"config.movable ?? true\"\n [resizable]=\"config.resizable ?? true\"\n [keepInViewport]=\"config.keepInViewport ?? true\"\n [snap]=\"config.snap ?? 'none'\"\n [dragHandle]=\"config.dragHandle ?? null\"\n [showMinimize]=\"config.showMinimize ?? null\"\n [showMaximize]=\"config.showMaximize ?? null\"\n [showClose]=\"config.showClose ?? true\"\n (closed)=\"ref.close()\"\n #window\n>\n <ng-container #content />\n</wr-window>\n\n@if (window.snapTarget(); as target) {\n <div class=\"wr-window__snap-hint\" [attr.data-target]=\"target\" aria-hidden=\"true\"></div>\n}\n", dependencies: [{ kind: "component", type: WrWindow, selector: "wr-window", inputs: ["open", "state", "title", "initialX", "initialY", "size", "initialWidth", "initialHeight", "os", "chromeSize", "animations", "minWidth", "minHeight", "maxWidth", "maxHeight", "movable", "resizable", "keepInViewport", "snap", "dragHandle", "showMinimize", "showMaximize", "showClose"], outputs: ["openChange", "stateChange", "closed", "moved", "resized"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
751
751
  }
752
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowContainer, decorators: [{
752
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowContainer, decorators: [{
753
753
  type: Component,
754
754
  args: [{ selector: 'wr-window-container', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, imports: [WrWindow], template: "<wr-window\n [open]=\"true\"\n [title]=\"ref.title()\"\n [os]=\"config.os ?? 'auto'\"\n [size]=\"config.size ?? 'md'\"\n [chromeSize]=\"config.chromeSize ?? 'normal'\"\n [animations]=\"config.animations ?? true\"\n [initialX]=\"config.x ?? null\"\n [initialY]=\"config.y ?? null\"\n [initialWidth]=\"config.width ?? null\"\n [initialHeight]=\"config.height ?? null\"\n [minWidth]=\"config.minWidth ?? 220\"\n [minHeight]=\"config.minHeight ?? 140\"\n [maxWidth]=\"config.maxWidth ?? 1000000\"\n [maxHeight]=\"config.maxHeight ?? 1000000\"\n [movable]=\"config.movable ?? true\"\n [resizable]=\"config.resizable ?? true\"\n [keepInViewport]=\"config.keepInViewport ?? true\"\n [snap]=\"config.snap ?? 'none'\"\n [dragHandle]=\"config.dragHandle ?? null\"\n [showMinimize]=\"config.showMinimize ?? null\"\n [showMaximize]=\"config.showMaximize ?? null\"\n [showClose]=\"config.showClose ?? true\"\n (closed)=\"ref.close()\"\n #window\n>\n <ng-container #content />\n</wr-window>\n\n@if (window.snapTarget(); as target) {\n <div class=\"wr-window__snap-hint\" [attr.data-target]=\"target\" aria-hidden=\"true\"></div>\n}\n" }]
755
755
  }], ctorParameters: () => [], propDecorators: { contentVcr: [{ type: i0.ViewChild, args: ['content', { ...{ read: ViewContainerRef }, isSignal: true }] }], wrWindow: [{ type: i0.ViewChild, args: [i0.forwardRef(() => WrWindow), { isSignal: true }] }] } });
@@ -1270,10 +1270,10 @@ class WrWindowManager {
1270
1270
  clearLayout(name) {
1271
1271
  this.storage.remove(this.layoutKey(name));
1272
1272
  }
1273
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowManager, deps: [], target: i0.ɵɵFactoryTarget.Service });
1274
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.2", ngImport: i0, type: WrWindowManager });
1273
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowManager, deps: [], target: i0.ɵɵFactoryTarget.Service });
1274
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.1.4", ngImport: i0, type: WrWindowManager });
1275
1275
  }
1276
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowManager, decorators: [{
1276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowManager, decorators: [{
1277
1277
  type: Service
1278
1278
  }] });
1279
1279
 
@@ -1336,10 +1336,10 @@ class WrWindowTaskbar {
1336
1336
  event.stopPropagation();
1337
1337
  void ref.close();
1338
1338
  }
1339
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowTaskbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1340
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: WrWindowTaskbar, isStandalone: true, selector: "wr-window-taskbar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "toolbar" }, properties: { "class": "classes()", "attr.aria-label": "railLabel()" } }, ngImport: i0, template: "@if (items().length > 0) {\n <div class=\"wr-window-taskbar__rail\">\n @for (ref of items(); track ref.id) {\n <!--\n Two SIBLING buttons in a plain container, not a close button nested\n inside the tab. The close used to be a `role=\"button\"` span with\n `tabindex=\"0\"` inside the tab's own `<button>` \u2014 interactive content\n inside interactive content, which the HTML parser and `nested-interactive`\n both object to. Nothing caught it: a taskbar tab exists only while a\n window is minimized, and the a11y sweep reads prerendered HTML, where the\n rail is not rendered at all.\n -->\n <div class=\"wr-window-taskbar__tab\">\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-restore\"\n [attr.aria-label]=\"restoreLabel({ title: tabTitle(ref) })\"\n (click)=\"restore(ref)\"\n >\n <span class=\"wr-window-taskbar__tab-title\">{{ tabTitle(ref) }}</span>\n </button>\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close(ref, $event)\"\n >\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M1 1 L9 9 M9 1 L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n </div>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowTaskbar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.4", type: WrWindowTaskbar, isStandalone: true, selector: "wr-window-taskbar", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "toolbar" }, properties: { "class": "classes()", "attr.aria-label": "railLabel()" } }, ngImport: i0, template: "@if (items().length > 0) {\n <div class=\"wr-window-taskbar__rail\">\n @for (ref of items(); track ref.id) {\n <!--\n Two SIBLING buttons in a plain container, not a close button nested\n inside the tab. The close used to be a `role=\"button\"` span with\n `tabindex=\"0\"` inside the tab's own `<button>` \u2014 interactive content\n inside interactive content, which the HTML parser and `nested-interactive`\n both object to. Nothing caught it: a taskbar tab exists only while a\n window is minimized, and the a11y sweep reads prerendered HTML, where the\n rail is not rendered at all.\n -->\n <div class=\"wr-window-taskbar__tab\">\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-restore\"\n [attr.aria-label]=\"restoreLabel({ title: tabTitle(ref) })\"\n (click)=\"restore(ref)\"\n >\n <span class=\"wr-window-taskbar__tab-title\">{{ tabTitle(ref) }}</span>\n </button>\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close(ref, $event)\"\n >\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M1 1 L9 9 M9 1 L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n </div>\n }\n </div>\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1341
1341
  }
1342
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.2", ngImport: i0, type: WrWindowTaskbar, decorators: [{
1342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrWindowTaskbar, decorators: [{
1343
1343
  type: Component,
1344
1344
  args: [{ selector: 'wr-window-taskbar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()', role: 'toolbar', '[attr.aria-label]': 'railLabel()' }, template: "@if (items().length > 0) {\n <div class=\"wr-window-taskbar__rail\">\n @for (ref of items(); track ref.id) {\n <!--\n Two SIBLING buttons in a plain container, not a close button nested\n inside the tab. The close used to be a `role=\"button\"` span with\n `tabindex=\"0\"` inside the tab's own `<button>` \u2014 interactive content\n inside interactive content, which the HTML parser and `nested-interactive`\n both object to. Nothing caught it: a taskbar tab exists only while a\n window is minimized, and the a11y sweep reads prerendered HTML, where the\n rail is not rendered at all.\n -->\n <div class=\"wr-window-taskbar__tab\">\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-restore\"\n [attr.aria-label]=\"restoreLabel({ title: tabTitle(ref) })\"\n (click)=\"restore(ref)\"\n >\n <span class=\"wr-window-taskbar__tab-title\">{{ tabTitle(ref) }}</span>\n </button>\n <button\n type=\"button\"\n class=\"wr-window-taskbar__tab-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close(ref, $event)\"\n >\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M1 1 L9 9 M9 1 L1 9\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n </button>\n </div>\n }\n </div>\n}\n" }]
1345
1345
  }], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }] } });
package/llms-full.txt CHANGED
@@ -732,7 +732,7 @@
732
732
  - import: `import { WrSegmented } from 'ngwr/segmented'`
733
733
  - selector: `wr-segmented`
734
734
  - exports: WrSegmented, WrSegmentedOption, WrSegmentedSize
735
- - Single-choice picker rendered as a segmented control. Two-way binds the selected value.
735
+ - Single-choice picker rendered as a segmented control. A signal-forms native control — it implements `FormValueControl`, so `[formField]` binds straight to its `value` model. `[(value)]` works standalone, and `[(ngModel)]` / reactive forms keep working through Angular's bridge.
736
736
 
737
737
  ## ngwr/segmented/testing
738
738
  - import: `import { WrSegmentedHarness } from 'ngwr/segmented/testing'`
package/llms.txt CHANGED
@@ -132,8 +132,10 @@ before writing your own. Full catalog: https://ngwr.dev/reference/components.
132
132
 
133
133
  ## Patterns
134
134
 
135
- - **Forms** — every value control is signal-forms native (`FormValueControl`, or
136
- `FormCheckboxControl` for checkbox) — no `ControlValueAccessor` in between.
135
+ - **Forms** — nineteen value controls are signal-forms native (`FormValueControl`,
136
+ or `FormCheckboxControl` for checkbox/switch) — no `ControlValueAccessor` in the
137
+ library. A count rather than "every": `[wrColorPickerTrigger]` is public, carries
138
+ its own `value` model, and implements neither.
137
139
  Bind `[formField]="form.x"`, use the two-way model standalone (`[(value)]`, or
138
140
  `[(checked)]` on checkbox/switch), or classic `[(ngModel)]` / reactive forms
139
141
  via Angular's bridge.
@@ -191,6 +193,26 @@ before writing your own. Full catalog: https://ngwr.dev/reference/components.
191
193
  EXCLUSIVE. `editable` turns on drag and resize; `Alt` + arrows do the same
192
194
  from the keyboard.
193
195
 
196
+ ## Deciding whether to use it
197
+
198
+ Three pages exist for the question before installation, and everything on them
199
+ is meant to be checkable rather than taken on trust:
200
+
201
+ - **Why ngwr, and when not to** — the wedge (nineteen value controls are Signal
202
+ Forms controls; no `ControlValueAccessor` in the library), a comparison against
203
+ Material / PrimeNG / NG-ZORRO / Taiga / Spartan, and a per-competitor "choose
204
+ something else if" section: https://ngwr.dev/start/comparison
205
+ - **What gates a change** — eight gates on every PR, three separate
206
+ accessibility sweeps and what each one cannot see, the two nightly baselines
207
+ and what is accepted in them, plus what the test suite does NOT cover:
208
+ https://ngwr.dev/start/quality
209
+ - **A live Signal Forms demo** you can read before installing anything:
210
+ https://ngwr.dev/start/playground
211
+
212
+ The honest shape of the project, since these pages say it too: one maintainer,
213
+ MIT, six majors shipped between 2026-06-12 and 2026-08-20, a codemod for every
214
+ break a codemod can repair, no commercial support.
215
+
194
216
  ## Resources (machine-readable)
195
217
 
196
218
  - This quick-ref: https://ngwr.dev/llms.txt
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngwr",
3
- "version": "12.0.0",
3
+ "version": "12.1.0",
4
4
  "bin": {
5
5
  "ngwr-mcp": "./mcp/server.js"
6
6
  },
@@ -111,6 +111,17 @@ declare class WrPagination {
111
111
  protected readonly navLabel: _angular_core.Signal<string>;
112
112
  /** Internal: total page count. */
113
113
  protected readonly totalPages: _angular_core.Signal<number>;
114
+ /**
115
+ * Internal: where the previous arrow goes. Clamped to the end of the valid
116
+ * range rather than being a plain `currentPage() - 1`, because the page can
117
+ * legitimately sit past that end while `total` is 0 (see the guard effect).
118
+ * From page 5 of one page, `goTo(4)` is refused as out of range, so the arrow
119
+ * was enabled and did nothing — and under `responsive` on a narrow box the
120
+ * numbered cells are hidden by a container query, which left no way back at
121
+ * all. `Math.min` only ever moves the target INWARD, so `goTo`'s own
122
+ * past-the-end refusal keeps working as the backstop it is.
123
+ */
124
+ protected readonly prevPage: _angular_core.Signal<number>;
114
125
  /** Internal: "X–Y of Z" string. */
115
126
  protected readonly rangeLabel: _angular_core.Signal<string>;
116
127
  /**
@@ -194,6 +194,17 @@ declare class WrSegmentedOptionHarness extends ComponentHarness {
194
194
  * - Activation is the browser's own default action on a button, which jsdom does not
195
195
  * implement, so {@link select} clicks — see {@link WrSegmentedOptionHarness.select}.
196
196
  *
197
+ * **It is a signal-forms control**, which adds two things to read here and one that
198
+ * cannot be read at all. `[formField]` binds the component's own `value` model, and a
199
+ * surrounding `<wr-form-field>` publishes its state onto the GROUP —
200
+ * {@link isInvalid} and {@link getDescriptionText} answer that, on the host rather
201
+ * than per segment, because the strip is one field and a description repeated on
202
+ * every segment would be announced once per Tab. What is NOT here is the field's
203
+ * `touched` flag: the component only emits `touch`, and whether anything listened is
204
+ * a fact about the form, not about this DOM — assert it on the field.
205
+ * {@link blur} is how a spec gets there, and it is the ONLY route: a click does not
206
+ * mark a field touched, and neither does moving from one segment to the next.
207
+ *
197
208
  * **There is deliberately no `getValue()` and no selection by value.** `options` is
198
209
  * a bound array of `{ value, label, … }` and the value is a generic `T` the component
199
210
  * writes nowhere — not on the host, not on a segment. The single exception is an
@@ -339,6 +350,39 @@ declare class WrSegmentedHarness extends ComponentHarness {
339
350
  * {@link getTabStopLabels} gives.
340
351
  */
341
352
  getFocusedLabel(): Promise<string | null>;
353
+ /**
354
+ * Whether the surrounding `<wr-form-field>` is reporting this control invalid, from
355
+ * `aria-invalid` on the host.
356
+ *
357
+ * `false` for a control with no field around it, and `false` for a field that is
358
+ * invalid but has not shown its copy yet: the component keys the attribute on the
359
+ * MESSAGE existing rather than on the error, because announcing "invalid" while
360
+ * pointing at nothing is worse than staying quiet. So this and
361
+ * {@link getDescriptionText} move together, and a `true` with no description would
362
+ * be the finding.
363
+ */
364
+ isInvalid(): Promise<boolean>;
365
+ /**
366
+ * The text `aria-describedby` points at — the validation copy a screen reader is
367
+ * given for this control — or `null` when the host describes nothing.
368
+ *
369
+ * Resolved from the document root, because the element named may sit anywhere on
370
+ * the page, and THROWS when the reference resolves to no element: a dangling
371
+ * `aria-describedby` renders exactly like a working one and is announced as
372
+ * nothing, so returning `null` for it would report the bug as the healthy state.
373
+ */
374
+ getDescriptionText(): Promise<string | null>;
375
+ /**
376
+ * Take focus off the strip entirely — what marks a bound field touched, and the
377
+ * only thing that does.
378
+ *
379
+ * The component emits `touch` from a `focusout` that leaves the host, so a click
380
+ * does not reach it and neither does Tab from one segment to the next: a strip a
381
+ * user tabbed straight past has to end up untouched, which is the case `touched`
382
+ * exists for. Resolves quietly when nothing inside was focused, since that is
383
+ * already the state this asks for.
384
+ */
385
+ blur(): Promise<void>;
342
386
  /**
343
387
  * The index the component publishes for the thumb, from the
344
388
  * `--wr-segmented-thumb-index` custom property it sets inline.
@@ -1,4 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
+ import { FormValueControl } from '@angular/forms/signals';
2
3
  import { WrIconName } from 'ngwr/icon';
3
4
 
4
5
  /**
@@ -31,8 +32,25 @@ interface WrSegmentedOption<T = unknown> {
31
32
  * Single-choice picker rendered as a segmented control. Two-way binds
32
33
  * the selected `value`.
33
34
  *
35
+ * A signal-forms native control: it implements `FormValueControl<T | null>`, so
36
+ * `[formField]` binds straight to its `value` model — no
37
+ * `ControlValueAccessor` in between. `[(value)]` works standalone, and classic
38
+ * `[(ngModel)]` / reactive forms keep working through Angular's bridge.
39
+ *
40
+ * It stays a `role="group"` of `aria-pressed` toggle buttons rather than
41
+ * becoming a `radiogroup`: being a form control changes what the value is bound
42
+ * to, not what the widget is, and a radiogroup would owe a roving tab stop and
43
+ * arrow-key selection — a different keyboard contract for every consumer who
44
+ * already ships this. The group is what the field describes (`aria-describedby`
45
+ * / `aria-invalid` land on the host), while the `<label for>` has to name a
46
+ * labelable element, so the id goes on the first segment.
47
+ *
34
48
  * @example
35
49
  * ```html
50
+ * <!-- signal forms -->
51
+ * <wr-segmented [options]="ranges" [formField]="form.range" />
52
+ *
53
+ * <!-- standalone two-way binding -->
36
54
  * <wr-segmented
37
55
  * [options]="[
38
56
  * { value: 'day', label: 'Day' },
@@ -46,15 +64,68 @@ interface WrSegmentedOption<T = unknown> {
46
64
  * @see https://ngwr.dev/reference/components/segmented
47
65
  */
48
66
  type WrSegmentedSize = 'sm' | 'md' | 'lg';
49
- declare class WrSegmented<T = unknown> {
67
+ declare class WrSegmented<T = unknown> implements FormValueControl<T | null> {
50
68
  /** The segments to render. */
51
69
  readonly options: _angular_core.InputSignal<readonly WrSegmentedOption<T>[]>;
52
- /** Two-way bindable selected value. */
70
+ /**
71
+ * The picked segment's `value`, `null` when nothing is selected. Bound by
72
+ * `[formField]`, or two-way via `[(value)]`.
73
+ */
53
74
  readonly value: _angular_core.ModelSignal<T | null>;
54
- /** Disable the whole control. @default false */
75
+ /** Emitted when focus leaves the strip, so a bound field can mark itself touched. */
76
+ readonly touch: _angular_core.OutputEmitterRef<void>;
77
+ /**
78
+ * Disable the whole control. Bound automatically from the field's disabled
79
+ * state when used with `[formField]`.
80
+ *
81
+ * @default false
82
+ */
55
83
  readonly disabled: _angular_core.InputSignalWithTransform<boolean, any>;
56
84
  /** Control size — shares the `--wr-control-*` contract. @default 'md' */
57
85
  readonly size: _angular_core.InputSignal<WrSegmentedSize>;
86
+ private readonly host;
87
+ private readonly field;
88
+ /**
89
+ * Id the surrounding `<wr-form-field>`'s `<label for>` points at, stamped on the
90
+ * FIRST segment.
91
+ *
92
+ * The field renders its label before it can see what was projected into it, so the
93
+ * id travels the other way and the control adopts it, exactly as `[wrInput]`,
94
+ * `wr-slider` and `wr-select` do. Without this the `for` named an element that was
95
+ * nowhere in the document: clicking the label did nothing.
96
+ *
97
+ * It cannot go on the host — only a labelable element can be a label's target, and
98
+ * `<wr-segmented>` is not one — and there is no single control to put it on, so it
99
+ * goes where clicking the label should land a user: the first segment, which is
100
+ * also the strip's first tab stop. The same choice `wr-slider` makes with its low
101
+ * thumb.
102
+ *
103
+ * What this does NOT change is that segment's NAME: it is named by its own label,
104
+ * and a `<label for>` cannot outrank text content in the accname order anyway.
105
+ *
106
+ * The one shape this reads wrong is a strip NESTED inside another control that is
107
+ * itself the field — `<wr-color-picker>`'s own format tabs are the only case in
108
+ * the library — where the id lands on a tab instead of on the picker. That is the
109
+ * same exposure `[wrInput]`, `wr-slider` and `wr-select` all carry, and the fix
110
+ * belongs to the outer control (shield its subtree by providing `WR_FORM_FIELD`
111
+ * as `null`), not to a strip that cannot tell whose field it is in.
112
+ */
113
+ protected readonly controlId: _angular_core.Signal<string | null>;
114
+ /**
115
+ * The field's error message, wired to the GROUP rather than to a segment.
116
+ *
117
+ * A segmented control is one field made of several buttons, so the description
118
+ * belongs to the thing the field describes — repeated on every segment it would be
119
+ * announced once per Tab. `role="group"` supports neither state as a role-specific
120
+ * attribute, but both are ARIA globals, so this is valid where an `aria-checked`
121
+ * would not be.
122
+ *
123
+ * `aria-invalid` is keyed on the message EXISTING rather than on `errorKeys()`,
124
+ * because the field only publishes an id once it is showing something — announcing
125
+ * "invalid" while pointing at nothing is worse than staying quiet.
126
+ */
127
+ protected readonly describedBy: _angular_core.Signal<string | null>;
128
+ protected readonly ariaInvalid: _angular_core.Signal<"true" | null>;
58
129
  /** Index of the selected option, or `-1` when nothing is selected. */
59
130
  protected readonly selectedIndex: _angular_core.Signal<number>;
60
131
  /** Flips true after the first paint so the thumb only animates user-driven changes, not the initial snap. */
@@ -86,8 +157,19 @@ declare class WrSegmented<T = unknown> {
86
157
  protected isSelected(option: WrSegmentedOption<T>): boolean;
87
158
  protected select(option: WrSegmentedOption<T>): void;
88
159
  protected trackByValue(_: number, option: WrSegmentedOption<T>): unknown;
160
+ /**
161
+ * A bound field learns it may show its validation copy from `touch`, and a click
162
+ * cannot be the source: a strip tabbed into and out of without a pick left the
163
+ * field untouched forever — which is exactly the case `touched` exists for.
164
+ *
165
+ * `wr-knob` and `wr-rating` bind `(blur)` on the one element they own; this
166
+ * component owns one button per option, so it listens for the bubbling `focusout`
167
+ * on its host instead — and ignores the one that only moves focus from one segment
168
+ * to the next, the way `wr-slider` ignores the hop between its two thumbs.
169
+ */
170
+ protected onFocusOut(event: FocusEvent): void;
89
171
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrSegmented<any>, never>;
90
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrSegmented<any>, "wr-segmented", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; }, never, never, true, never>;
172
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrSegmented<any>, "wr-segmented", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "value": { "alias": "value"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; }, { "value": "valueChange"; "touch": "touch"; }, never, never, true, never>;
91
173
  }
92
174
 
93
175
  export { WrSegmented };
@@ -16,7 +16,7 @@ import { InjectionToken } from '@angular/core';
16
16
  * Distinct from `Version` exported by `@angular/core`, which reports the
17
17
  * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.
18
18
  */
19
- declare const NGWR_VERSION = "12.0.0";
19
+ declare const NGWR_VERSION = "12.1.0";
20
20
 
21
21
  /**
22
22
  * @license