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.
- package/LICENSE +1 -1
- package/README.md +5 -3
- package/alert/styles/_index.scss +2 -0
- package/back-top/styles/_index.scss +4 -2
- package/carousel/styles/_index.scss +2 -0
- package/cascader/styles/_index.scss +16 -0
- package/color-picker/styles/_index.scss +7 -0
- package/command-palette/styles/_index.scss +28 -0
- package/density/styles/_index.scss +10 -0
- package/descriptions/styles/_index.scss +59 -0
- package/dialog/styles/_index.scss +2 -0
- package/drawer/styles/_index.scss +2 -0
- package/dropdown/styles/_index.scss +1 -0
- package/fesm2022/ngwr-carousel.mjs +45 -4
- package/fesm2022/ngwr-carousel.mjs.map +1 -1
- package/fesm2022/ngwr-cascader.mjs +2 -2
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette.mjs +17 -3
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +77 -5
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-density.mjs +3 -3
- package/fesm2022/ngwr-density.mjs.map +1 -1
- package/fesm2022/ngwr-descriptions.mjs +11 -2
- package/fesm2022/ngwr-descriptions.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +11 -4
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +13 -3
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +66 -5
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +35 -11
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-lightbox.mjs +45 -2
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +70 -1
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-page-header.mjs +11 -3
- package/fesm2022/ngwr-page-header.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +11 -3
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-popover.mjs +36 -10
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-rotating-text.mjs +15 -4
- package/fesm2022/ngwr-rotating-text.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +35 -14
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-stepper.mjs +11 -2
- package/fesm2022/ngwr-stepper.mjs.map +1 -1
- package/fesm2022/ngwr-table.mjs +10 -4
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +38 -6
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-toast.mjs +54 -2
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-toolbar.mjs +11 -4
- package/fesm2022/ngwr-toolbar.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/lightbox/styles/_index.scss +4 -0
- package/llms-full.txt +673 -0
- package/llms.txt +106 -0
- package/overlay/styles/_index.scss +31 -0
- package/package.json +6 -5
- package/page-header/styles/_index.scss +16 -0
- package/pagination/styles/_index.scss +34 -0
- package/popover/styles/_index.scss +1 -0
- package/select/styles/_index.scss +27 -0
- package/slider/styles/_index.scss +3 -0
- package/splitter/styles/_index.scss +3 -0
- package/stepper/styles/_index.scss +30 -0
- package/styles.scss +1 -0
- package/table/styles/_index.scss +61 -0
- package/tabs/styles/_index.scss +24 -0
- package/theme/styles/_mixins.scss +47 -0
- package/toast/styles/_index.scss +32 -1
- package/toolbar/styles/_index.scss +29 -0
- package/tree/styles/_index.scss +15 -0
- package/types/ngwr-carousel.d.ts +8 -1
- package/types/ngwr-command-palette.d.ts +13 -1
- package/types/ngwr-context-menu.d.ts +25 -3
- package/types/ngwr-density.d.ts +2 -2
- package/types/ngwr-descriptions.d.ts +8 -1
- package/types/ngwr-dialog.d.ts +7 -0
- package/types/ngwr-drag-drop.d.ts +13 -1
- package/types/ngwr-drawer.d.ts +11 -3
- package/types/ngwr-dropdown.d.ts +10 -1
- package/types/ngwr-lightbox.d.ts +5 -0
- package/types/ngwr-overlay.d.ts +69 -1
- package/types/ngwr-page-header.d.ts +8 -1
- package/types/ngwr-pagination.d.ts +7 -1
- package/types/ngwr-popover.d.ts +10 -1
- package/types/ngwr-rotating-text.d.ts +1 -0
- package/types/ngwr-select.d.ts +10 -1
- package/types/ngwr-stepper.d.ts +8 -1
- package/types/ngwr-table.d.ts +7 -1
- package/types/ngwr-tabs.d.ts +6 -0
- package/types/ngwr-toolbar.d.ts +7 -1
- 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.
|
|
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-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
package/table/styles/_index.scss
CHANGED
|
@@ -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;
|
package/tabs/styles/_index.scss
CHANGED
|
@@ -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
|
+
}
|
package/toast/styles/_index.scss
CHANGED
|
@@ -20,7 +20,11 @@ $toast-colors: (
|
|
|
20
20
|
display: flex;
|
|
21
21
|
flex-direction: column;
|
|
22
22
|
gap: 0.5rem;
|
|
23
|
-
|
|
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
|
+
}
|
package/tree/styles/_index.scss
CHANGED
|
@@ -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
|
+
}
|
package/types/ngwr-carousel.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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
|
}
|