ngwr 7.1.0 → 7.3.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 (99) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -3
  3. package/alert/styles/_index.scss +2 -0
  4. package/back-top/styles/_index.scss +4 -2
  5. package/carousel/styles/_index.scss +2 -0
  6. package/cascader/styles/_index.scss +16 -0
  7. package/color-picker/styles/_index.scss +7 -0
  8. package/command-palette/styles/_index.scss +28 -0
  9. package/density/styles/_index.scss +10 -0
  10. package/descriptions/styles/_index.scss +59 -0
  11. package/dialog/styles/_index.scss +2 -0
  12. package/drawer/styles/_index.scss +2 -0
  13. package/dropdown/styles/_index.scss +1 -0
  14. package/fesm2022/ngwr-carousel.mjs +45 -4
  15. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  16. package/fesm2022/ngwr-cascader.mjs +2 -2
  17. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  18. package/fesm2022/ngwr-command-palette.mjs +17 -3
  19. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  20. package/fesm2022/ngwr-context-menu.mjs +77 -5
  21. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  22. package/fesm2022/ngwr-density.mjs +3 -3
  23. package/fesm2022/ngwr-density.mjs.map +1 -1
  24. package/fesm2022/ngwr-descriptions.mjs +11 -2
  25. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  26. package/fesm2022/ngwr-dialog.mjs +11 -4
  27. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  28. package/fesm2022/ngwr-drag-drop.mjs +13 -3
  29. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  30. package/fesm2022/ngwr-drawer.mjs +66 -5
  31. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  32. package/fesm2022/ngwr-dropdown.mjs +35 -11
  33. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  34. package/fesm2022/ngwr-lightbox.mjs +45 -2
  35. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  36. package/fesm2022/ngwr-overlay.mjs +70 -1
  37. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  38. package/fesm2022/ngwr-page-header.mjs +11 -3
  39. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  40. package/fesm2022/ngwr-pagination.mjs +11 -3
  41. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  42. package/fesm2022/ngwr-popover.mjs +36 -10
  43. package/fesm2022/ngwr-popover.mjs.map +1 -1
  44. package/fesm2022/ngwr-rotating-text.mjs +15 -4
  45. package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
  46. package/fesm2022/ngwr-select.mjs +35 -14
  47. package/fesm2022/ngwr-select.mjs.map +1 -1
  48. package/fesm2022/ngwr-stepper.mjs +11 -2
  49. package/fesm2022/ngwr-stepper.mjs.map +1 -1
  50. package/fesm2022/ngwr-table.mjs +10 -4
  51. package/fesm2022/ngwr-table.mjs.map +1 -1
  52. package/fesm2022/ngwr-tabs.mjs +38 -6
  53. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  54. package/fesm2022/ngwr-toast.mjs +54 -2
  55. package/fesm2022/ngwr-toast.mjs.map +1 -1
  56. package/fesm2022/ngwr-toolbar.mjs +11 -4
  57. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  58. package/fesm2022/ngwr-version.mjs +1 -1
  59. package/fesm2022/ngwr-version.mjs.map +1 -1
  60. package/lightbox/styles/_index.scss +4 -0
  61. package/llms-full.txt +673 -0
  62. package/llms.txt +106 -0
  63. package/overlay/styles/_index.scss +31 -0
  64. package/package.json +6 -5
  65. package/page-header/styles/_index.scss +16 -0
  66. package/pagination/styles/_index.scss +34 -0
  67. package/popover/styles/_index.scss +1 -0
  68. package/select/styles/_index.scss +27 -0
  69. package/slider/styles/_index.scss +3 -0
  70. package/splitter/styles/_index.scss +3 -0
  71. package/stepper/styles/_index.scss +30 -0
  72. package/styles.scss +1 -0
  73. package/table/styles/_index.scss +61 -0
  74. package/tabs/styles/_index.scss +24 -0
  75. package/theme/styles/_mixins.scss +47 -0
  76. package/toast/styles/_index.scss +32 -1
  77. package/toolbar/styles/_index.scss +29 -0
  78. package/tree/styles/_index.scss +15 -0
  79. package/types/ngwr-carousel.d.ts +8 -1
  80. package/types/ngwr-command-palette.d.ts +13 -1
  81. package/types/ngwr-context-menu.d.ts +25 -3
  82. package/types/ngwr-density.d.ts +2 -2
  83. package/types/ngwr-descriptions.d.ts +8 -1
  84. package/types/ngwr-dialog.d.ts +7 -0
  85. package/types/ngwr-drag-drop.d.ts +13 -1
  86. package/types/ngwr-drawer.d.ts +11 -3
  87. package/types/ngwr-dropdown.d.ts +10 -1
  88. package/types/ngwr-lightbox.d.ts +5 -0
  89. package/types/ngwr-overlay.d.ts +69 -1
  90. package/types/ngwr-page-header.d.ts +8 -1
  91. package/types/ngwr-pagination.d.ts +7 -1
  92. package/types/ngwr-popover.d.ts +10 -1
  93. package/types/ngwr-rotating-text.d.ts +1 -0
  94. package/types/ngwr-select.d.ts +10 -1
  95. package/types/ngwr-stepper.d.ts +8 -1
  96. package/types/ngwr-table.d.ts +7 -1
  97. package/types/ngwr-tabs.d.ts +6 -0
  98. package/types/ngwr-toolbar.d.ts +7 -1
  99. package/types/ngwr-version.d.ts +1 -1
package/llms.txt ADDED
@@ -0,0 +1,106 @@
1
+ # ngwr
2
+
3
+ > Angular UI library — standalone, signals-first, zoneless, fully tree-shakable.
4
+ > ~124 components built on `@angular/cdk` primitives. The only runtime dependency
5
+ > is `tslib`. Docs and live demos: https://ngwr.dev — source:
6
+ > https://github.com/thekhegay/ngwr
7
+
8
+ This file orients AI agents and LLMs that consume ngwr. For exact, current
9
+ component APIs, read the bundled TypeScript types (`node_modules/ngwr/<name>`).
10
+ Note: **ngwr.dev is a single-page app** — fetching its routes returns a JS shell,
11
+ not text. Use the machine-readable resources listed at the bottom instead.
12
+
13
+ ## Install
14
+
15
+ Preferred — the schematic installs ngwr, wires the providers + styles, and
16
+ prints a tailored bootstrap snippet:
17
+
18
+ ```
19
+ ng add ngwr
20
+ ```
21
+
22
+ Or add it manually (pnpm / npm / yarn):
23
+
24
+ ```
25
+ pnpm add ngwr @angular/cdk
26
+ ```
27
+
28
+ Each component is a tree-shakable subpath import: `import { WrButton } from
29
+ 'ngwr/button'`. Styles: `@use 'ngwr'` (everything) or `@use 'ngwr/<name>'` (per
30
+ component) in your global SCSS.
31
+
32
+ ## Providers (main.ts)
33
+
34
+ Add from their entry points as needed:
35
+
36
+ - `provideWrOverlay()` — required for any overlay (dialog / select / dropdown /
37
+ popover / toast / drawer). Add `provideWrResponsiveOverlays()` for mobile sheets.
38
+ - `provideWrIcons(lucideIcons({ check: Check }))` — icon registry (`ngwr/icon`,
39
+ adapters under `ngwr/icon/adapters/*`).
40
+ - `provideWrTheme()` — `--wr-*` design tokens. `provideWrDensity()` — sizing.
41
+ - `provideWrI18n(...)` + `provideWrI18nStaticLoader(...)` — localization.
42
+ - `provideWrDateAdapter(...)` — calendar + date-picker (`ngwr/date-adapter-fns`
43
+ or `ngwr/date-adapter-luxon`).
44
+
45
+ ## Schematics — let `ng` wire it
46
+
47
+ - `ng add ngwr` — installs peers, adds `@use 'ngwr'` to styles, prints provider setup.
48
+ - `ng g ngwr:use WrFoo src/app/x.ts` — adds the import + splices `WrFoo` into that
49
+ component's `@Component` imports.
50
+ - `ng g ngwr:provider <overlay|icons|toast|i18n|date-adapter|density|theme|…>` —
51
+ adds the matching `provideWr*()` to bootstrap.
52
+ - `ng g ngwr:icon-set` — scaffolds a tree-shaken icon barrel.
53
+ - `ng g ngwr:component-style <name>` — appends `@use 'ngwr/<name>'` (opt-in styles).
54
+ - `ng g ngwr:page <form|table|dashboard>` — starter page wired with ngwr.
55
+ - `ng update ngwr` — runs upgrade migrations.
56
+
57
+ ## Use ngwr — don't hand-roll
58
+
59
+ The catalog is large: prefer an ngwr component, util, pipe, or validator over raw
60
+ markup, custom logic, or another library. e.g. use `wr-file-upload`, not a bare
61
+ `<input type="file">`; reach for `ngwr/utils`, `ngwr/pipes`, `ngwr/validators`
62
+ before writing your own. Full catalog: https://ngwr.dev/components.
63
+
64
+ ## Common components (selector — import)
65
+
66
+ - **Form** — `wr-btn` (ngwr/button), `wrInput` (ngwr/input), `wr-select`
67
+ (ngwr/select; modes single/multi/search/tag), `wr-checkbox`, `wr-switch`,
68
+ `wr-slider`, `wr-input-number`, `wr-input-otp`, `wr-date-picker`
69
+ (date/time/datetime), `wr-file-upload`, `wr-form-field`, `wr-color-picker`.
70
+ - **Data** — `wr-table`, `wr-pagination`, `wr-tree`, `wr-virtual-scroll`,
71
+ `wr-sortable-list` (drag-to-reorder).
72
+ - **Feedback** — `wr-alert`, `wr-toast`, `wr-result`, `wr-empty`, `wr-skeleton`,
73
+ `wr-spinner`.
74
+ - **Layout / Display** — `wr-card`, `wr-carousel`, `wr-collapse`, `wr-splitter`,
75
+ `wr-toolbar`, `wr-descriptions`, `wr-statistic`, `wr-lightbox`.
76
+ - **Navigation** — `wr-tabs`, `wr-stepper`, `wr-breadcrumbs`, `wr-dropdown-menu`.
77
+ - **Overlays** — `wr-drawer`, `wr-popover` (has a `tooltip` mode),
78
+ `wr-command-palette`, `wr-context-menu`, `wr-popconfirm`. (Dialog is
79
+ service-opened.)
80
+
81
+ ## Patterns
82
+
83
+ - **Forms** — components are ControlValueAccessors → bind `[formField]="form.x"`
84
+ (Signal Forms) or `[(ngModel)]`.
85
+ - **Icons** — register via `provideWrIcons`, render `<wr-icon name="check" />`.
86
+ - **i18n** — `{{ 'key' | wrT }}` (pipe from `ngwr/i18n`).
87
+ - **Theme** — CSS custom properties `--wr-color-*`, `--wr-border-radius-*`, … set
88
+ by `provideWrTheme()`.
89
+ - **Mobile** — overlays collapse to sheets (`provideWrResponsiveOverlays()`), a
90
+ `responsive` input reflows layout components, and a `touch` density preset
91
+ enlarges controls.
92
+
93
+ ## Resources (machine-readable)
94
+
95
+ ngwr.dev is a single-page app, so its HTML routes return a JS shell with no
96
+ content. Read these instead:
97
+
98
+ - This quick-ref: https://ngwr.dev/llms.txt
99
+ - Full reference (every entry point + selector + description):
100
+ https://ngwr.dev/llms-full.txt
101
+ - All site URLs (for crawlers): https://ngwr.dev/sitemap.xml
102
+ - Source, README, per-component `.d.ts` types: https://github.com/thekhegay/ngwr
103
+ (installed at `node_modules/ngwr/<name>`; the package also ships `README.md`,
104
+ `llms.txt`, and `llms-full.txt`)
105
+
106
+ Human-facing live demos (JS, for people): https://ngwr.dev.
@@ -0,0 +1,31 @@
1
+ // Shared presentation styles for responsive (bottom-sheet) overlays.
2
+ // Added to a component's overlay panel (`wr-dialog-panel`,
3
+ // `wr-select-overlay`, …) when `provideWrResponsiveOverlays()` or a
4
+ // component's `responsive` option pins the overlay to the bottom edge on
5
+ // small viewports. `!important` so it wins over each component's own panel
6
+ // sizing regardless of stylesheet order.
7
+
8
+ .wr-overlay-sheet {
9
+ width: 100% !important;
10
+ min-width: 0 !important;
11
+ max-width: 100% !important;
12
+ max-height: 90vh !important;
13
+ border-radius: var(--wr-border-radius-lg) var(--wr-border-radius-lg) 0 0 !important;
14
+ padding-bottom: env(safe-area-inset-bottom);
15
+ animation: wr-overlay-sheet-up var(--wr-overlay-duration, 0.2s) var(--wr-overlay-ease, ease-out) !important;
16
+ }
17
+
18
+ // Dim + blur behind a sheet — for overlays that otherwise have no backdrop.
19
+ .wr-overlay-backdrop {
20
+ background: rgba(var(--wr-color-backdrop-rgb), 0.45);
21
+ backdrop-filter: blur(2px);
22
+ }
23
+
24
+ @keyframes wr-overlay-sheet-up {
25
+ from {
26
+ transform: translateY(100%);
27
+ }
28
+ to {
29
+ transform: translateY(0);
30
+ }
31
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngwr",
3
- "version": "7.1.0",
3
+ "version": "7.3.0",
4
4
  "license": "MIT",
5
5
  "description": "NGWR – Angular UI components library",
6
6
  "author": "Roman Khegay <rk@garuna.dev> (https://garuna.dev)",
@@ -367,6 +367,11 @@
367
367
  "types": "./types/ngwr-meter-group.d.ts",
368
368
  "default": "./fesm2022/ngwr-meter-group.mjs"
369
369
  },
370
+ "./overlay": {
371
+ "sass": "./overlay/styles/_index.scss",
372
+ "types": "./types/ngwr-overlay.d.ts",
373
+ "default": "./fesm2022/ngwr-overlay.mjs"
374
+ },
370
375
  "./page-header": {
371
376
  "sass": "./page-header/styles/_index.scss",
372
377
  "types": "./types/ngwr-page-header.d.ts",
@@ -647,10 +652,6 @@
647
652
  "types": "./types/ngwr-meta.d.ts",
648
653
  "default": "./fesm2022/ngwr-meta.mjs"
649
654
  },
650
- "./overlay": {
651
- "types": "./types/ngwr-overlay.d.ts",
652
- "default": "./fesm2022/ngwr-overlay.mjs"
653
- },
654
655
  "./pipes": {
655
656
  "types": "./types/ngwr-pipes.d.ts",
656
657
  "default": "./fesm2022/ngwr-pipes.mjs"
@@ -12,6 +12,13 @@
12
12
  border-bottom: 1px solid var(--wr-color-light);
13
13
  font-family: var(--wr-font-family-base);
14
14
 
15
+ // Opt-in (`responsive`): query the box's own width so the title + actions row
16
+ // stacks when the header is too narrow to sit them side by side. The host is
17
+ // already full-width, so containment is safe here.
18
+ &--responsive {
19
+ container: wr-page-header / inline-size;
20
+ }
21
+
15
22
  &__breadcrumbs {
16
23
  font-size: var(--wr-text-sm);
17
24
  color: var(--wr-color-medium);
@@ -76,3 +83,12 @@
76
83
  }
77
84
  }
78
85
  }
86
+
87
+ // Responsive headers stack the title above the actions when their own box is
88
+ // too narrow to sit them side by side (regardless of viewport).
89
+ @container wr-page-header (max-width: 32rem) {
90
+ .wr-page-header--responsive .wr-page-header__main {
91
+ flex-direction: column;
92
+ align-items: flex-start;
93
+ }
94
+ }
@@ -8,6 +8,14 @@
8
8
  pointer-events: none;
9
9
  }
10
10
 
11
+ // Opt-in (`responsive`): query the control's own width so it collapses to a
12
+ // compact pager when narrow. `inline-size` containment drops content-based
13
+ // sizing, so pin the box to its container's width.
14
+ &--responsive {
15
+ container: wr-pagination / inline-size;
16
+ width: 100%;
17
+ }
18
+
11
19
  &__inner {
12
20
  display: flex;
13
21
  align-items: center;
@@ -57,6 +65,19 @@
57
65
  user-select: none;
58
66
  }
59
67
 
68
+ // Compact pager label ("3 / 10"). Hidden until responsive mode swaps it in
69
+ // for the numbered cells on a narrow box.
70
+ &__current {
71
+ display: none;
72
+ align-items: center;
73
+ padding: 0 0.375rem;
74
+ color: var(--wr-color-dark);
75
+ font-family: var(--wr-font-family-base);
76
+ font-size: 0.8125rem;
77
+ font-variant-numeric: tabular-nums;
78
+ white-space: nowrap;
79
+ }
80
+
60
81
  &__size {
61
82
  min-width: 0;
62
83
  }
@@ -113,3 +134,16 @@
113
134
  border-bottom-right-radius: var(--wr-border-radius-sm);
114
135
  }
115
136
  }
137
+
138
+ // Responsive pagination collapses the numbered strip to a compact
139
+ // `‹ page / total ›` pager when its own box is too narrow.
140
+ @container wr-pagination (max-width: 24rem) {
141
+ .wr-pagination--responsive .wr-pagination__page,
142
+ .wr-pagination--responsive .wr-pagination__ellipsis {
143
+ display: none;
144
+ }
145
+
146
+ .wr-pagination--responsive .wr-pagination__current {
147
+ display: inline-flex;
148
+ }
149
+ }
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../overlay/styles'; // shared .wr-overlay-sheet / .wr-overlay-backdrop for responsive mode
2
3
 
3
4
  .wr-popover-overlay {
4
5
  > * {
@@ -1,4 +1,5 @@
1
1
  @use '../../theme/styles' as theme;
2
+ @use '../../overlay/styles'; // shared .wr-overlay-sheet / .wr-overlay-backdrop for responsive mode
2
3
 
3
4
  .wr-select {
4
5
  --wr-select-color: var(--wr-color-dark);
@@ -321,3 +322,29 @@
321
322
  padding-top: 0.25rem;
322
323
  }
323
324
  }
325
+
326
+ // Touch pointers: grow the chip removes / clear button and open up the chip
327
+ // rows so each is a comfortable tap target without overlapping its neighbour.
328
+ // The removes reach ~32px in a ~44px-tall chip; fine pointers keep the
329
+ // compact desktop sizing above.
330
+ @media (pointer: coarse) {
331
+ .wr-select__chips {
332
+ gap: 0.375rem;
333
+ }
334
+
335
+ .wr-select__chip {
336
+ gap: 0.375rem;
337
+ padding: 0.375rem 0.5rem 0.375rem 0.75rem;
338
+ }
339
+
340
+ .wr-select__chip-remove,
341
+ .wr-select__clear {
342
+ --wr-icon-size: 1.125rem;
343
+ width: 2rem;
344
+ height: 2rem;
345
+ }
346
+
347
+ .wr-select__clear {
348
+ margin-right: 0;
349
+ }
350
+ }
@@ -49,6 +49,9 @@
49
49
  transform var(--wr-transition-short),
50
50
  box-shadow var(--wr-transition-base);
51
51
 
52
+ // Coarse pointers: invisible 44px tap area so the small thumb is grabbable.
53
+ @include theme.touch-target($positioned: true);
54
+
52
55
  &:focus-visible {
53
56
  outline: none;
54
57
  box-shadow: 0 0 0 3px rgba(var(--wr-color-primary-rgb), 0.25);
@@ -35,6 +35,9 @@
35
35
  outline: 0;
36
36
  transition: background var(--wr-transition-base);
37
37
 
38
+ // Coarse pointers: expand the 4px gutter to a 44px tap area.
39
+ @include theme.touch-target($positioned: true);
40
+
38
41
  &:hover,
39
42
  &:focus-visible {
40
43
  background: var(--wr-color-primary);
@@ -14,6 +14,13 @@
14
14
  gap: 1rem;
15
15
  font-family: var(--wr-font-family-base);
16
16
 
17
+ // Opt-in (`responsive`): query the box's own width so a horizontal stepper
18
+ // can drop to vertical when its column is too narrow. The host is already
19
+ // full-width, so containment is safe here.
20
+ &--responsive {
21
+ container: wr-stepper / inline-size;
22
+ }
23
+
17
24
  &__headers {
18
25
  list-style: none;
19
26
  margin: 0;
@@ -151,6 +158,29 @@
151
158
  }
152
159
  }
153
160
 
161
+ // Responsive horizontal steppers fall back to the vertical layout when their
162
+ // own box is too narrow for the row — mirrors the `--vertical` rules above,
163
+ // scoped to responsive steppers that aren't already vertical.
164
+ @container wr-stepper (max-width: 32rem) {
165
+ .wr-stepper--responsive:not(.wr-stepper--vertical) .wr-stepper__headers {
166
+ flex-direction: column;
167
+ }
168
+
169
+ .wr-stepper--responsive:not(.wr-stepper--vertical) .wr-stepper__header {
170
+ align-items: stretch;
171
+ flex: 0 0 auto;
172
+ }
173
+
174
+ .wr-stepper--responsive:not(.wr-stepper--vertical) .wr-stepper__connector {
175
+ width: 1.5px;
176
+ min-height: 1.25rem;
177
+ height: auto;
178
+ margin: 0.25rem 0 0.25rem calc(var(--wr-stepper-indicator-size) / 2);
179
+ align-self: stretch;
180
+ flex: 0 0 auto;
181
+ }
182
+ }
183
+
154
184
  // `<wr-step>` itself — visibility is driven by an `--active` class
155
185
  // the stepper toggles via host binding.
156
186
  .wr-step {
package/styles.scss CHANGED
@@ -74,6 +74,7 @@
74
74
  @forward './marquee/styles';
75
75
  @forward './mention/styles';
76
76
  @forward './meter-group/styles';
77
+ @forward './overlay/styles';
77
78
  @forward './page-header/styles';
78
79
  @forward './pagination/styles';
79
80
  @forward './popconfirm/styles';
@@ -14,6 +14,13 @@
14
14
  font-family: var(--wr-font-family-base);
15
15
  color: var(--wr-color-dark);
16
16
 
17
+ // Opt-in (`responsive`): query the table's own width so each row collapses to
18
+ // a labelled card when it's too narrow for columns. Already width:100%, so
19
+ // containment is safe.
20
+ &--responsive {
21
+ container: wr-table / inline-size;
22
+ }
23
+
17
24
  &__scroll {
18
25
  width: 100%;
19
26
  overflow-x: auto;
@@ -102,6 +109,60 @@
102
109
  }
103
110
  }
104
111
 
112
+ // Responsive tables: when the box is too narrow for columns, each row becomes a
113
+ // card and every cell shows its column title (from `data-label`) as a label.
114
+ @container wr-table (max-width: 36rem) {
115
+ .wr-table--responsive .wr-table__scroll {
116
+ overflow-x: visible;
117
+ }
118
+
119
+ // Break the table grid down to blocks; the header row is replaced by per-cell
120
+ // labels.
121
+ .wr-table--responsive .wr-table__table,
122
+ .wr-table--responsive .wr-table__table tbody,
123
+ .wr-table--responsive .wr-table__tr,
124
+ .wr-table--responsive .wr-table__td {
125
+ display: block;
126
+ }
127
+
128
+ .wr-table--responsive .wr-table__table thead {
129
+ display: none;
130
+ }
131
+
132
+ // One card per row.
133
+ .wr-table--responsive .wr-table__tr {
134
+ padding: 0.375rem 0;
135
+ border-bottom: 1px solid var(--wr-table-border);
136
+ }
137
+
138
+ .wr-table--responsive .wr-table__tr:last-child {
139
+ border-bottom: 0;
140
+ }
141
+
142
+ // Each cell is a `LABEL ......... value` line.
143
+ .wr-table--responsive .wr-table__td {
144
+ display: flex;
145
+ justify-content: space-between;
146
+ align-items: baseline;
147
+ gap: 1rem;
148
+ padding: 0.25rem 0.875rem;
149
+ border-bottom: 0;
150
+ text-align: right;
151
+ }
152
+
153
+ .wr-table--responsive .wr-table__td::before {
154
+ content: attr(data-label);
155
+ flex: 0 0 auto;
156
+ color: var(--wr-color-medium);
157
+ font-size: 0.6875rem;
158
+ font-weight: 600;
159
+ letter-spacing: 0.04em;
160
+ text-transform: uppercase;
161
+ text-align: left;
162
+ white-space: nowrap;
163
+ }
164
+ }
165
+
105
166
  .wr-table-sort {
106
167
  display: inline-flex;
107
168
  --wr-icon-size: 0.875rem;
@@ -29,6 +29,30 @@
29
29
  // the y-axis since the strip is always a single row.
30
30
  overflow-x: auto;
31
31
  overflow-y: hidden;
32
+
33
+ // Edge fades — when the strip overflows, the side that still has tabs to
34
+ // scroll to fades out, cueing that there's more. `--wr-tabs-fade-*` default
35
+ // to 0 (no fade); the `--fade-start` / `--fade-end` modifiers below turn an
36
+ // edge on from the component's scroll metrics, so a non-scrolling strip is
37
+ // never masked.
38
+ --wr-tabs-fade: 1.5rem;
39
+ --wr-tabs-fade-start: 0px;
40
+ --wr-tabs-fade-end: 0px;
41
+ mask-image: linear-gradient(
42
+ to right,
43
+ transparent 0,
44
+ #000 var(--wr-tabs-fade-start),
45
+ #000 calc(100% - var(--wr-tabs-fade-end)),
46
+ transparent 100%
47
+ );
48
+ }
49
+
50
+ &--fade-start &__strip {
51
+ --wr-tabs-fade-start: var(--wr-tabs-fade);
52
+ }
53
+
54
+ &--fade-end &__strip {
55
+ --wr-tabs-fade-end: var(--wr-tabs-fade);
32
56
  }
33
57
 
34
58
  &__tab {
@@ -55,3 +55,50 @@
55
55
  border-radius: calc(#{$br} * 1.85);
56
56
  }
57
57
  }
58
+
59
+ /// Expand a small control's touch hit area to a comfortable minimum on
60
+ /// coarse (touch) pointers, without changing how it looks. Lays an
61
+ /// invisible, centred `::after` over the control that's at least `$size`
62
+ /// square; taps on the slack still land on the host. Fine-pointer
63
+ /// (mouse / trackpad) layouts are left exactly as-is, so dense desktop
64
+ /// UIs keep their tight targets.
65
+ ///
66
+ /// Use on small icon-only controls — close (×) buttons, chip removes,
67
+ /// tree / cascader toggles — where the visible glyph is well under the
68
+ /// ~44px comfortable tap size. Skip controls that are already tall
69
+ /// enough, and avoid it on tightly-packed rows where a 44px slack would
70
+ /// overlap a neighbouring target.
71
+ ///
72
+ /// The pseudo is absolutely positioned, so the host must be a containing
73
+ /// block. For the common static control the mixin sets `position:
74
+ /// relative` for you; pass `$positioned: true` when the host is already
75
+ /// `absolute` / `fixed` / `relative` so the mixin doesn't downgrade its
76
+ /// positioning under the media query.
77
+ ///
78
+ /// @param {Length} $size [44px] - Minimum hit-area edge (Apple HIG).
79
+ /// @param {Bool} $positioned [false] - Set true if the host already
80
+ /// establishes a positioning context (skips `position: relative`).
81
+ ///
82
+ /// @example scss
83
+ /// .wr-alert__close {
84
+ /// @include touch-target;
85
+ /// }
86
+ @mixin touch-target($size: 44px, $positioned: false) {
87
+ @media (pointer: coarse) {
88
+ @if not $positioned {
89
+ position: relative;
90
+ }
91
+
92
+ &::after {
93
+ content: '';
94
+ position: absolute;
95
+ top: 50%;
96
+ left: 50%;
97
+ width: 100%;
98
+ height: 100%;
99
+ min-width: $size;
100
+ min-height: $size;
101
+ transform: translate(-50%, -50%);
102
+ }
103
+ }
104
+ }
@@ -20,7 +20,11 @@ $toast-colors: (
20
20
  display: flex;
21
21
  flex-direction: column;
22
22
  gap: 0.5rem;
23
- padding: 1rem;
23
+ // Safe-area: fold each inset into the matching padding side so toasts clear
24
+ // notches / the home indicator / rounded corners on mobile, whichever edge
25
+ // the host is anchored to. env() is 0 without insets, so desktop stays 1rem.
26
+ padding: calc(1rem + env(safe-area-inset-top)) calc(1rem + env(safe-area-inset-right))
27
+ calc(1rem + env(safe-area-inset-bottom)) calc(1rem + env(safe-area-inset-left));
24
28
  pointer-events: none;
25
29
  max-width: 22rem;
26
30
  width: 100%;
@@ -126,6 +130,8 @@ $toast-colors: (
126
130
  padding: 0.75rem 0.875rem;
127
131
  background: var(--wr-toast-bg);
128
132
  border: 1px solid var(--wr-toast-border);
133
+ // Capture horizontal swipe-to-dismiss; let vertical scroll pass through.
134
+ touch-action: pan-y;
129
135
  border-left: 3px solid var(--wr-toast-accent);
130
136
  @include theme.smooth-br(var(--wr-border-radius-base));
131
137
  box-shadow: var(--wr-shadow-overlay);
@@ -261,3 +267,28 @@ $toast-colors: (
261
267
  order: 99;
262
268
  align-self: stretch;
263
269
  }
270
+
271
+ // Touch pointers: grow the per-toast action buttons (copy / dismiss) to ~32px
272
+ // with a wider gap so the pair no longer sits 2px apart, and give the
273
+ // dismiss-all bar a taller hit area. Fine pointers keep the compact desktop
274
+ // sizing above.
275
+ @media (pointer: coarse) {
276
+ .wr-toast__actions {
277
+ gap: 0.25rem;
278
+ }
279
+
280
+ .wr-toast__action {
281
+ display: inline-flex;
282
+ align-items: center;
283
+ justify-content: center;
284
+ width: 2rem;
285
+ height: 2rem;
286
+ padding: 0;
287
+ --wr-icon-size: 1.125rem;
288
+ }
289
+
290
+ .wr-toast-host__close-all {
291
+ padding-top: 0.75rem;
292
+ padding-bottom: 0.75rem;
293
+ }
294
+ }
@@ -20,6 +20,16 @@
20
20
  font-family: var(--wr-font-family-base);
21
21
  color: var(--wr-color-dark);
22
22
 
23
+ // Opt-in (`responsive`): query the toolbar's own width so the zones stack
24
+ // when it's too narrow for a row. Already full-width, so containment is safe.
25
+ // `flex-wrap` lives here (not in the `@container` below) because a container
26
+ // query can't style the query container itself — only its descendants; wrap
27
+ // only kicks in once the zones go full-width at the breakpoint.
28
+ &--responsive {
29
+ container: wr-toolbar / inline-size;
30
+ flex-wrap: wrap;
31
+ }
32
+
23
33
  &__zone {
24
34
  display: flex;
25
35
  align-items: center;
@@ -63,3 +73,22 @@
63
73
  }
64
74
  }
65
75
  }
76
+
77
+ // Responsive toolbars stack their zones when the bar is too narrow for a row.
78
+ @container wr-toolbar (max-width: 32rem) {
79
+ .wr-toolbar--responsive .wr-toolbar__zone {
80
+ flex: 1 1 100%;
81
+ justify-content: flex-start;
82
+ }
83
+
84
+ .wr-toolbar--responsive .wr-toolbar__zone--end {
85
+ margin-left: 0;
86
+ }
87
+
88
+ // The vertical hairline dividers are a horizontal-row affordance — drop them
89
+ // once the zones stack.
90
+ .wr-toolbar--responsive .wr-toolbar__zone--start + .wr-toolbar__zone--center::before,
91
+ .wr-toolbar--responsive .wr-toolbar__zone--center + .wr-toolbar__zone--end::before {
92
+ display: none;
93
+ }
94
+ }
@@ -269,3 +269,18 @@
269
269
  max-height: var(--wr-tree-panel-max-height, 18rem);
270
270
  overflow-y: auto;
271
271
  }
272
+
273
+ // Touch pointers: taller rows (~44px) and a larger expand/collapse toggle so
274
+ // both the row and its toggle are comfortable tap targets. Fine pointers keep
275
+ // the compact desktop rows above.
276
+ @media (pointer: coarse) {
277
+ .wr-tree__row {
278
+ padding-top: 0.5rem;
279
+ padding-bottom: 0.5rem;
280
+ }
281
+
282
+ .wr-tree__toggle {
283
+ width: 1.75rem;
284
+ height: 1.75rem;
285
+ }
286
+ }
@@ -39,7 +39,10 @@ declare class WrCarousel {
39
39
  readonly loop: _angular_core.InputSignalWithTransform<boolean, any>;
40
40
  protected readonly slides: _angular_core.Signal<readonly WrCarouselSlide[]>;
41
41
  protected readonly count: _angular_core.Signal<number>;
42
- /** CSS transform for the track. */
42
+ /** Live horizontal drag offset (px) during a touch swipe. */
43
+ protected readonly dragX: _angular_core.WritableSignal<number>;
44
+ protected readonly dragging: _angular_core.WritableSignal<boolean>;
45
+ /** CSS transform for the track — the per-slide offset plus any live drag. */
43
46
  protected readonly trackStyle: _angular_core.Signal<string>;
44
47
  private timer;
45
48
  private readonly paused;
@@ -50,6 +53,10 @@ declare class WrCarousel {
50
53
  goTo(index: number): void;
51
54
  next(): void;
52
55
  prev(): void;
56
+ private swipeStartX;
57
+ protected onSwipeStart(event: TouchEvent): void;
58
+ protected onSwipeMove(event: TouchEvent): void;
59
+ protected onSwipeEnd(event: TouchEvent, viewport: HTMLElement): void;
53
60
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<WrCarousel, never>;
54
61
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<WrCarousel, "wr-carousel", never, { "active": { "alias": "active"; "required": false; "isSignal": true; }; "showArrows": { "alias": "showArrows"; "required": false; "isSignal": true; }; "showDots": { "alias": "showDots"; "required": false; "isSignal": true; }; "autoplay": { "alias": "autoplay"; "required": false; "isSignal": true; }; "intervalMs": { "alias": "intervalMs"; "required": false; "isSignal": true; }; "loop": { "alias": "loop"; "required": false; "isSignal": true; }; }, { "active": "activeChange"; }, ["slides"], ["*"], true, never>;
55
62
  }