@guildofgleks/ui 21.3.2 → 21.4.1
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/AGENTS.md +212 -10
- package/README.md +102 -271
- package/TOKENS.md +2 -2
- package/fesm2022/guildofgleks-ui.mjs +641 -64
- package/fesm2022/guildofgleks-ui.mjs.map +1 -1
- package/package.json +11 -1
- package/src/styles/button.css +193 -0
- package/src/styles/index.css +2 -0
- package/src/styles/theme.css +6 -0
- package/styles/button.css +193 -0
- package/styles/index.css +2 -0
- package/styles/theme.css +6 -0
- package/types/guildofgleks-ui.d.ts +394 -15
package/README.md
CHANGED
|
@@ -4,184 +4,126 @@
|
|
|
4
4
|

|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
dependencies are `@angular/core`, `@angular/common` and `@angular/forms`.
|
|
7
|
+
# @guildofgleks/ui
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Features
|
|
13
|
-
|
|
14
|
-
- 27 standalone components and 2 directives — see [Components](#components) for the full
|
|
15
|
-
list — plus `DialogService`, `ToastService` and `ThemeService`.
|
|
16
|
-
- Signal-based API throughout: `input()` / `output()` / `model()`, `OnPush` change
|
|
17
|
-
detection, no NgModules.
|
|
18
|
-
- No CDK, no Material — a small dependency footprint on top of `@angular/core`,
|
|
19
|
-
`@angular/common` and `@angular/forms`.
|
|
20
|
-
- Full theming through CSS custom properties: restyle any component, swap the whole
|
|
21
|
-
palette, or ship light/dark and custom themes at runtime via a `data-theme` attribute.
|
|
22
|
-
- `ControlValueAccessor` on every form control (checkbox, inputfield, select,
|
|
23
|
-
multiselect, slider, textarea) — built and tested against Reactive Forms (`formControl` /
|
|
24
|
-
`formControlName`). The library does not use `ngModel`/`FormsModule` anywhere itself,
|
|
25
|
-
and template-driven usage via `[(ngModel)]` is untested — CVA makes it likely to work,
|
|
26
|
-
but it isn't a supported or verified path.
|
|
27
|
-
- Accessible by default: keyboard navigation, ARIA attributes, WCAG AA contrast.
|
|
28
|
-
|
|
29
|
-
## Install
|
|
30
|
-
|
|
31
|
-
npm:
|
|
9
|
+
An Angular 21 component library with **no CDK and no Material**. 27 components, 5 directives and
|
|
10
|
+
3 services, all standalone, all signal-based, themed entirely through CSS custom properties.
|
|
32
11
|
|
|
33
12
|
```bash
|
|
34
13
|
npm install @guildofgleks/ui
|
|
35
14
|
```
|
|
36
15
|
|
|
37
|
-
|
|
16
|
+
## Why this one
|
|
38
17
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
18
|
+
- **Small dependency footprint.** Peers are `@angular/core`, `@angular/common`, `@angular/forms`
|
|
19
|
+
and `@angular/platform-browser`. No router, no CDK, no animations package. `tslib` is the only
|
|
20
|
+
runtime dependency.
|
|
21
|
+
- **Signals throughout.** `input()` / `output()` / `model()`, `OnPush` everywhere, no NgModules.
|
|
22
|
+
- **Themeable without a build step.** Every value a component paints with is a `--gog-*` custom
|
|
23
|
+
property. Swap a palette, restyle one component, or override a single instance — no Sass
|
|
24
|
+
variables, no JS theme object.
|
|
25
|
+
- **Reactive Forms native.** Every form control is a `ControlValueAccessor` built and tested
|
|
26
|
+
against `[formControl]` / `formControlName`.
|
|
27
|
+
- **Your data, your shapes.** Dropdowns take your objects with accessor paths
|
|
28
|
+
(`optionLabel="profile.fullName"`), not a mandated `{ id, name }` DTO.
|
|
29
|
+
- **Accessible by default.** Keyboard navigation, ARIA wiring and generated label associations
|
|
30
|
+
come with the components rather than with extra attributes.
|
|
42
31
|
|
|
43
32
|
## Setup
|
|
44
33
|
|
|
45
|
-
Add the stylesheet
|
|
46
|
-
|
|
47
|
-
render unstyled.
|
|
34
|
+
**1. Add the stylesheet.** It carries the baseline theme and the utility classes the components
|
|
35
|
+
use — without it they render unstyled.
|
|
48
36
|
|
|
49
37
|
```jsonc
|
|
50
38
|
// angular.json → projects.<app>.architect.build.options
|
|
51
39
|
"styles": [
|
|
52
40
|
"node_modules/@guildofgleks/ui/styles/index.css",
|
|
53
|
-
"src/styles.scss" //
|
|
41
|
+
"src/styles.scss" // yours, after the baseline so it wins
|
|
54
42
|
]
|
|
55
43
|
```
|
|
56
44
|
|
|
57
|
-
> Up to 21.3.1
|
|
58
|
-
>
|
|
45
|
+
> Up to 21.3.1 these files shipped under `@guildofgleks/ui/src/styles/…`. That path keeps working
|
|
46
|
+
> until 21.5.0; new setups should use the shorter one.
|
|
59
47
|
|
|
60
|
-
|
|
48
|
+
**2. Import components where you use them** — each is standalone:
|
|
61
49
|
|
|
62
50
|
```ts
|
|
63
|
-
import { Component } from '@angular/core';
|
|
64
51
|
import { ButtonComponent, SelectComponent } from '@guildofgleks/ui';
|
|
65
52
|
|
|
66
53
|
@Component({
|
|
67
|
-
selector: 'app-example',
|
|
68
54
|
imports: [ButtonComponent, SelectComponent],
|
|
69
55
|
template: `
|
|
70
56
|
<gog-select label="Region" [options]="regions" [(value)]="region" />
|
|
71
57
|
<gog-button (gogClick)="save()">Save</gog-button>
|
|
72
58
|
`,
|
|
73
59
|
})
|
|
74
|
-
export class ExampleComponent {
|
|
75
|
-
/* … */
|
|
76
|
-
}
|
|
60
|
+
export class ExampleComponent {}
|
|
77
61
|
```
|
|
78
62
|
|
|
79
|
-
Outputs are prefixed
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
### Services need a host element
|
|
63
|
+
Outputs are prefixed `gog` (`gogClick`, `gogToggle`) so they never collide with native DOM
|
|
64
|
+
events. Inputs keep their natural names.
|
|
83
65
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`show()` update state and nothing appears on screen.** Put both in your root template — they
|
|
87
|
-
render nothing until something is actually open:
|
|
66
|
+
**3. If you use dialogs or toasts, place their hosts once.** `DialogService.open()` and
|
|
67
|
+
`ToastService.show()` update state but render nothing without them:
|
|
88
68
|
|
|
89
69
|
```ts
|
|
90
|
-
import { Component, inject } from '@angular/core';
|
|
91
|
-
import { DialogComponent, ToastContainerComponent, ToastService } from '@guildofgleks/ui';
|
|
92
|
-
|
|
93
70
|
@Component({
|
|
94
71
|
selector: 'app-root',
|
|
95
72
|
imports: [DialogComponent, ToastContainerComponent],
|
|
96
73
|
template: `
|
|
97
74
|
<router-outlet />
|
|
98
|
-
|
|
99
75
|
<gog-dialog />
|
|
100
76
|
<gog-toast-container />
|
|
101
77
|
`,
|
|
102
78
|
})
|
|
103
|
-
export class App {
|
|
104
|
-
private readonly toasts = inject(ToastService);
|
|
105
|
-
notify = () => this.toasts.show({ message: 'Saved', type: 'success' });
|
|
106
|
-
}
|
|
79
|
+
export class App {}
|
|
107
80
|
```
|
|
108
81
|
|
|
109
|
-
`<gog-dialog />` hosts every dialog
|
|
110
|
-
|
|
111
|
-
takes an optional `maxVisiblePerPosition` (default `5`).
|
|
82
|
+
One `<gog-dialog />` hosts every dialog (they stack); one `<gog-toast-container />` hosts all
|
|
83
|
+
four toast corners.
|
|
112
84
|
|
|
113
85
|
## Theming
|
|
114
86
|
|
|
115
|
-
|
|
116
|
-
paint with lives in `styles/theme.css`** — no component stylesheet holds a colour, font,
|
|
117
|
-
border, radius, shadow, spacing or duration of its own. There are three layers:
|
|
87
|
+
Every value the components paint with lives in `styles/theme.css`, in three layers:
|
|
118
88
|
|
|
119
|
-
**
|
|
120
|
-
|
|
121
|
-
so a palette swap carries through without touching anything else.
|
|
89
|
+
**Foundation** — palette, type scale, spacing, motion. Override these to restyle everything at
|
|
90
|
+
once; component tokens derive from them, so a palette swap carries through on its own.
|
|
122
91
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
available at runtime as `GOG_TOKEN_GROUPS`, typed by `GogTokenName`.
|
|
126
|
-
|
|
127
|
-
**2. Component tokens** — `--gog-<block>-*`, one block per component in `theme.css`, for
|
|
128
|
-
restyling a single component theme-wide. They cover every painted property, including
|
|
129
|
-
per-variant and per-size values (`--gog-btn-ghost-hover-bg`, `--gog-tag-lg-padding-block`,
|
|
130
|
-
`--gog-accordion-sm-chevron-size`, `--gog-skeleton-shine`, `--gog-paginator-gap`, …), plus
|
|
131
|
-
each component's font family, so a theme can decide that e.g. buttons use the body face:
|
|
92
|
+
**Component** — `--gog-<block>-*`, one block per component, to restyle a single component
|
|
93
|
+
app-wide:
|
|
132
94
|
|
|
133
95
|
```css
|
|
134
96
|
:root[data-theme='mine'] {
|
|
135
97
|
--gog-btn-font-family: var(--gog-font-body);
|
|
136
|
-
--gog-btn-font-weight: 600;
|
|
137
98
|
--gog-btn-ghost-hover-bg: color-mix(in srgb, var(--gog-accent-color) 20%, transparent);
|
|
138
99
|
--gog-table-hover-bg: var(--gog-hover-color);
|
|
139
100
|
}
|
|
140
101
|
```
|
|
141
102
|
|
|
142
|
-
**
|
|
143
|
-
|
|
144
|
-
hatch:
|
|
103
|
+
**Instance** — a small set left deliberately undeclared, so setting one anywhere beats the
|
|
104
|
+
variant and size classes:
|
|
145
105
|
|
|
146
106
|
```css
|
|
147
107
|
.my-form gog-button {
|
|
148
|
-
--gog-btn-bg: rebeccapurple; /*
|
|
108
|
+
--gog-btn-bg: rebeccapurple; /* wins over .gog-btn--primary */
|
|
149
109
|
}
|
|
150
110
|
```
|
|
151
111
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
`--gog-chip-{font-size,gap,padding-block,padding-inline,avatar-size,icon-size,remove-size}`,
|
|
155
|
-
the per-size field hooks (`--gog-input-padding-y`, `--gog-select-control-font`,
|
|
156
|
-
`--gog-ms-font-size`, `--gog-table-td-padding-v`, `--gog-accordion-padding-y`, …),
|
|
157
|
-
`--gog-spinner-color`, and `--gog-{input,select,ms}-float-label-on-bg` (the patch masking the
|
|
158
|
-
border behind an `'on'` label).
|
|
159
|
-
|
|
160
|
-
The full list is the `INSTANCE_TOKENS` set in `scripts/check-tokens.mjs`, which is verified
|
|
161
|
-
against the stylesheets on every CI run — an instance token that gets declared anywhere, or
|
|
162
|
-
stops being read, fails the build. That check also enforces the other half of the contract:
|
|
163
|
-
**no component stylesheet carries a default in a `var()` fallback**, so every value a
|
|
164
|
-
component paints with really is discoverable in `theme.css`.
|
|
165
|
-
|
|
166
|
-
The float label's _geometry_ is not instance-layer — it is themeable per component
|
|
167
|
-
(`--gog-{input,select,ms}-float-label-{reserve,in-top,over-gap,over-reserve}`), and all three
|
|
168
|
-
derive from the shared `--gog-field-float-label-*` scale above, so one declaration retunes
|
|
169
|
-
every field at once while a single control can still be overridden on its own.
|
|
112
|
+
Every group and token name is in **[`TOKENS.md`](./TOKENS.md)**, generated from `theme.css` so it
|
|
113
|
+
cannot drift, and available at runtime as `GOG_TOKEN_GROUPS`.
|
|
170
114
|
|
|
171
|
-
### Light and
|
|
115
|
+
### Light, dark and your own
|
|
172
116
|
|
|
173
|
-
The theme is
|
|
174
|
-
manages it:
|
|
117
|
+
The active theme is a `data-theme` attribute on `:root`, managed by `ThemeService`:
|
|
175
118
|
|
|
176
119
|
```ts
|
|
177
120
|
private readonly theme = inject(ThemeService);
|
|
178
|
-
this.theme.toggleTheme();
|
|
179
|
-
this.theme.setTheme('cyberpunk'); // any
|
|
180
|
-
this.theme.theme(); // read-only signal — go through the two methods above
|
|
121
|
+
this.theme.toggleTheme(); // light ⇄ dark
|
|
122
|
+
this.theme.setTheme('cyberpunk'); // any name you declared in CSS
|
|
181
123
|
```
|
|
182
124
|
|
|
183
|
-
Out of the box it adopts whatever `data-theme` is already on the document, or `
|
|
184
|
-
Persisting the choice and following the OS setting are opt-in
|
|
125
|
+
Out of the box it adopts whatever `data-theme` is already on the document, or `light`.
|
|
126
|
+
Persisting the choice and following the OS setting are opt-in:
|
|
185
127
|
|
|
186
128
|
```ts
|
|
187
129
|
provideGogConfig({
|
|
@@ -189,108 +131,46 @@ provideGogConfig({
|
|
|
189
131
|
});
|
|
190
132
|
```
|
|
191
133
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
component without listing any of them:
|
|
196
|
-
|
|
197
|
-
```css
|
|
198
|
-
:root[data-theme='cyberpunk'],
|
|
199
|
-
[data-theme='cyberpunk'] {
|
|
200
|
-
color-scheme: dark;
|
|
201
|
-
--gog-background-color: #050816;
|
|
202
|
-
--gog-accent-color: #ff4edb;
|
|
203
|
-
--gog-radius: 22px;
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
The second selector is what lets a theme apply to a _subtree_ rather than the whole page
|
|
208
|
-
— put `data-theme="cyberpunk"` on any element and everything inside it re-derives from
|
|
209
|
-
that palette, so one page can show several themes side by side (see the showcase's Theme
|
|
210
|
-
lab). That works because `theme.css` re-declares its derived layer on `:root, [data-theme]`:
|
|
211
|
-
a custom property's `var()` references are substituted where the property is _declared_,
|
|
212
|
-
so a derived token declared only on `:root` would freeze to the root palette.
|
|
213
|
-
|
|
214
|
-
Corollary worth knowing when writing your own themes: **anything you declare that reads
|
|
215
|
-
another token must sit on the theme scope itself**, not on `:root`, or it will not follow
|
|
216
|
-
a nested theme.
|
|
217
|
-
|
|
218
|
-
### Presets
|
|
219
|
-
|
|
220
|
-
`theme.css` ships `light` and `dark`. `slate` is a third, importable separately — a
|
|
221
|
-
palette-only theme in a cool/indigo register:
|
|
134
|
+
A theme only declares what it changes — the derived layer re-resolves against whatever palette is
|
|
135
|
+
in scope, so a new palette restyles every component without listing any of them. The `slate`
|
|
136
|
+
preset is the worked example, palette-only:
|
|
222
137
|
|
|
223
138
|
```css
|
|
224
139
|
@import '@guildofgleks/ui/styles/index.css';
|
|
225
140
|
@import '@guildofgleks/ui/styles/presets/slate.css';
|
|
226
141
|
```
|
|
227
142
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
It is worth reading as the worked example of the contract above: it declares **only palette
|
|
233
|
-
tokens** — no `--gog-btn-*`, no `--gog-table-*` — and still restyles every component, because
|
|
234
|
-
the derived layer re-resolves against whatever palette is in scope. If a theme of yours needs to
|
|
235
|
-
list component tokens, that usually means the derived layer is missing something rather than
|
|
236
|
-
that the theme needs to be longer.
|
|
143
|
+
Fonts are left alone on purpose (system stacks, no webfont download). Add
|
|
144
|
+
`@guildofgleks/ui/styles/fonts.css` for the showcase's typography.
|
|
237
145
|
|
|
238
|
-
|
|
146
|
+
## App-wide configuration
|
|
239
147
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
Google Fonts) add `@guildofgleks/ui/styles/fonts.css` as well.
|
|
243
|
-
|
|
244
|
-
## Global configuration
|
|
245
|
-
|
|
246
|
-
Anything visual is a CSS token (above). For the rest — the handful of settings an app would
|
|
247
|
-
otherwise repeat on every instance — there is one provider, not an injection token per
|
|
248
|
-
component per setting:
|
|
148
|
+
Anything visual is a token. Everything else — the settings you would otherwise repeat on every
|
|
149
|
+
instance — goes through one provider:
|
|
249
150
|
|
|
250
151
|
```ts
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
dropdown: { appendToBody: true },
|
|
258
|
-
datepicker: { locale: 'de-DE', format: 'dd.MM.yyyy' },
|
|
259
|
-
button: { debounce: 500 },
|
|
260
|
-
}),
|
|
261
|
-
];
|
|
152
|
+
provideGogConfig({
|
|
153
|
+
control: { size: 'sm', errorDisplay: 'auto', clearable: true },
|
|
154
|
+
dropdown: { appendToBody: true },
|
|
155
|
+
datepicker: { locale: 'de-DE', format: 'dd.MM.yyyy' },
|
|
156
|
+
labels: { clear: 'Очистить', selectAll: 'Выбрать все' }, // translate the library once
|
|
157
|
+
});
|
|
262
158
|
```
|
|
263
159
|
|
|
264
|
-
Keys: `control`, `dropdown`, `floatLabel`, `datepicker`, `autocomplete`, `inputfield`,
|
|
265
|
-
`
|
|
266
|
-
and
|
|
267
|
-
|
|
268
|
-
rather than replacing it, so a route can override one field and inherit the rest.
|
|
269
|
-
|
|
270
|
-
### Translating the library
|
|
160
|
+
Keys: `control`, `dropdown`, `floatLabel`, `datepicker`, `autocomplete`, `inputfield`, `textarea`,
|
|
161
|
+
`tooltip`, `scroll`, `button`, `paginator`, `toast`, `theme`, `labels`. An instance's own input
|
|
162
|
+
always wins, and providing the config again lower in the injector tree layers onto the parent
|
|
163
|
+
rather than replacing it.
|
|
271
164
|
|
|
272
|
-
|
|
273
|
-
markup for. Set them once instead of on every control:
|
|
165
|
+
Icons work the same way — 41 Lucide glyphs ship with the package, and your own register by name:
|
|
274
166
|
|
|
275
167
|
```ts
|
|
276
|
-
|
|
277
|
-
labels: {
|
|
278
|
-
clear: 'Очистить',
|
|
279
|
-
clearSelection: 'Очистить выбор',
|
|
280
|
-
selectAll: 'Выбрать все',
|
|
281
|
-
closeDialog: 'Закрыть',
|
|
282
|
-
previousPage: 'Предыдущая страница',
|
|
283
|
-
today: 'Сегодня',
|
|
284
|
-
// interpolating labels take a function, since word order and agreement vary by language
|
|
285
|
-
page: (page, isCurrent) =>
|
|
286
|
-
isCurrent ? `Страница ${page}, текущая` : `Перейти на страницу ${page}`,
|
|
287
|
-
},
|
|
288
|
-
});
|
|
168
|
+
provideGogIcons({ cart: '<svg viewBox="0 0 24 24">…</svg>' });
|
|
289
169
|
```
|
|
290
170
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
171
|
+
```html
|
|
172
|
+
<gog-icon name="cart" /> <gog-tag iconName="cart">In basket</gog-tag>
|
|
173
|
+
```
|
|
294
174
|
|
|
295
175
|
## Components
|
|
296
176
|
|
|
@@ -304,94 +184,45 @@ those stay per instance.
|
|
|
304
184
|
| Feedback | `gog-spinner`, `gog-spinner-overlay`, `gog-progressbar`, `gog-skeleton` |
|
|
305
185
|
| Content | `gog-icon` |
|
|
306
186
|
|
|
307
|
-
Directives
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
`gogAccordionHeader`, `gogAccordionContent`, `gogAccordionChevron`, `gogButtonToggleOption`,
|
|
311
|
-
`gogCheckboxIcon`, `gogColumnBody`, `gogColumnHeader`, `gogDropdownOption`,
|
|
312
|
-
`gogDropdownChevron`, `gogInputAddonStart`, `gogInputAddonEnd`, `gogMultiselectClearIcon`,
|
|
313
|
-
`gogTabHeader`, `gogTabContent`, `gogTagIcon`.
|
|
314
|
-
|
|
315
|
-
`gog-dialog` and `gog-toast-container` are the host elements the two services render into —
|
|
316
|
-
see [Services need a host element](#services-need-a-host-element).
|
|
187
|
+
**Directives:** `gogButton` (a link that looks like a button), `gogTooltip`, `gogBadge`,
|
|
188
|
+
`gogCollapsibleTrigger`, `gogCollapsibleContent`.
|
|
189
|
+
**Services:** `DialogService`, `ToastService`, `ThemeService`.
|
|
317
190
|
|
|
318
|
-
|
|
191
|
+
Fifteen more slot directives replace a component's markup rather than configuring it —
|
|
192
|
+
`gogColumnBody`, `gogInputAddonStart`, `gogDropdownOption` and friends.
|
|
319
193
|
|
|
320
|
-
|
|
321
|
-
Project any element as the trigger via `gogCollapsibleTrigger` and any element as the
|
|
322
|
-
panel via `gogCollapsibleContent`; `[(open)]` is two-way bindable. Useful for anything
|
|
323
|
-
that needs an inline expanding region without the overlay behavior of `gog-select`/
|
|
324
|
-
`gog-multiselect` — e.g. a collapsible group of links in a nav sidebar.
|
|
194
|
+
A few things worth knowing before you reach for a workaround:
|
|
325
195
|
|
|
326
|
-
|
|
196
|
+
- **`gog-table` works two ways.** By default it owns the data and sorts and pages in memory. With
|
|
197
|
+
`[lazy]="true"` it hands both to the server: `value` is the current page, `totalRecords` drives
|
|
198
|
+
the paginator, and `gogSortChange` / `gogPageChange` are your refetch signals. Row selection is
|
|
199
|
+
`selectionMode` + `[(selection)]`; set `dataKey` or a refetch drops it.
|
|
200
|
+
- **`gog-button` cannot be a link** — it renders its own `<button>`. Use `[gogButton]` on your own
|
|
201
|
+
`<a>` instead; nothing is brokered through inputs, so `routerLink`, `href` and `target` keep
|
|
202
|
+
working. That is also why this package needs no `@angular/router`.
|
|
203
|
+
- **`gog-inputfield` and `gog-textarea` forward the native attribute space** they wrap —
|
|
204
|
+
`readonly`, `maxlength`, `pattern`, `inputMode`, `spellcheck` and the text-field `type` values.
|
|
205
|
+
They also generate their own `id`, so labels and error messages are wired up without `inputId`.
|
|
206
|
+
- **`gog-collapsible` is headless** — no markup of its own. Project any element as the trigger and
|
|
207
|
+
any element as the panel.
|
|
208
|
+
- **`[(ngModel)]` is untested.** The library never imports `FormsModule`; use Reactive Forms.
|
|
327
209
|
|
|
328
|
-
|
|
329
|
-
`optionValue` and `optionDisabled` each take a property path — dot-paths included — or a
|
|
330
|
-
function:
|
|
331
|
-
|
|
332
|
-
```html
|
|
333
|
-
<gog-select
|
|
334
|
-
[options]="members"
|
|
335
|
-
optionLabel="profile.fullName"
|
|
336
|
-
optionValue="uuid"
|
|
337
|
-
optionDisabled="suspended"
|
|
338
|
-
[(value)]="memberId"
|
|
339
|
-
/>
|
|
340
|
-
```
|
|
210
|
+
## Documentation
|
|
341
211
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
<ng-template gogDropdownOption let-m let-label="label">
|
|
348
|
-
{{ label }} — {{ $any(m).profile.role }}
|
|
349
|
-
</ng-template>
|
|
350
|
-
</gog-select>
|
|
351
|
-
```
|
|
212
|
+
| | |
|
|
213
|
+
| --- | --- |
|
|
214
|
+
| **[`AGENTS.md`](./AGENTS.md)** | the full API reference — every input, output, slot, type and default, per component. Ships in this package. |
|
|
215
|
+
| **[`TOKENS.md`](./TOKENS.md)** | every `--gog-*` token, generated from `theme.css` |
|
|
216
|
+
| [CHANGELOG](https://github.com/GuildOfGleks/gleks_web_ui/blob/master/projects/gleks/ui/CHANGELOG.md) | release history |
|
|
352
217
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
`gogTooltip` is a hover/focus tooltip directive, not a component — drop it on any element,
|
|
357
|
-
a `gog-*` component's own host tag or a plain native one
|
|
358
|
-
(`<button gogTooltip="Save changes">`, `<gog-chip [gogTooltip]="hint">`). Content is a
|
|
359
|
-
string or a `TemplateRef`; `gogTooltipPosition` (`'auto'` default, or an explicit side),
|
|
360
|
-
`gogTooltipShowDelay` (`300`ms default), `gogTooltipHideDelay` (`100`ms default) and
|
|
361
|
-
`gogTooltipDisabled` inputs, the first three also configurable app-wide via
|
|
362
|
-
`GOG_CONFIG.tooltip`.
|
|
363
|
-
|
|
364
|
-
`gog-inputfield` and `gog-textarea` forward the native attribute space of the element they
|
|
365
|
-
wrap, so nothing is out of reach because it is hidden inside a component: `readonly`,
|
|
366
|
-
`maxlength`, `minlength`, `spellcheck`, plus `pattern` and `inputMode` on the input, and the
|
|
367
|
-
`type` values that render as a text field (`text`, `password`, `email`, `number`, `search`,
|
|
368
|
-
`tel`, `url`, `date`, `time`, `datetime-local` — see `GogInputType`). `readonly` keeps the
|
|
369
|
-
value focusable and submitted but blocks edits, so the clear button and a number field's
|
|
370
|
-
stepper both stand down while it is on. `autofocus` is deliberately **not** forwarded: moving
|
|
371
|
-
focus without the user asking is disorienting for keyboard and screen-reader users, and an app
|
|
372
|
-
that genuinely needs it can focus the element itself.
|
|
373
|
-
|
|
374
|
-
Every field also generates its own `id` when you don't pass `inputId`, so the label is always
|
|
375
|
-
associated with the control and the error message is always reachable through
|
|
376
|
-
`aria-describedby`. Pass `inputId` only when something outside the component has to reference
|
|
377
|
-
the field by a known id.
|
|
378
|
-
|
|
379
|
-
`gog-checkbox`, `gog-inputfield`, `gog-select`, `gog-multiselect`, `gog-slider` and
|
|
380
|
-
`gog-textarea` implement `ControlValueAccessor` and are built for Reactive Forms — use
|
|
381
|
-
`[formControl]` or `formControlName`. The library itself never imports `FormsModule` or
|
|
382
|
-
uses `ngModel`; `[(ngModel)]` is not tested against these components and isn't a
|
|
383
|
-
supported usage path. With a form control attached, the error message appears once the
|
|
384
|
-
control is both touched and invalid; without one it shows for as long as `errorMessage`
|
|
385
|
-
is non-empty, and the consumer decides when to clear it.
|
|
386
|
-
|
|
387
|
-
`gog-inputfield`, `gog-select`, `gog-multiselect` and `gog-textarea` all accept a
|
|
388
|
-
`floatLabel` input — `'in'` (floats up but stays inside the border), `'on'` (floats to sit
|
|
389
|
-
centered on the top border line) or `'over'` (floats fully above the field, outside the
|
|
390
|
-
border) — plus `floatLabelShowPlaceholder` to reveal the field's own `placeholder` once the
|
|
391
|
-
label has floated out of the way (it stays hidden the whole time otherwise, since the
|
|
392
|
-
resting label already sits where it would). Both default to off/`false` and are settable
|
|
393
|
-
per instance or app-wide via `GOG_CONFIG.floatLabel`.
|
|
218
|
+
`AGENTS.md` is written for an AI coding assistant working in your project, but it is the most
|
|
219
|
+
complete API reference either way — point your assistant at it and it will stop guessing.
|
|
394
220
|
|
|
395
221
|
## License
|
|
396
222
|
|
|
397
223
|
Apache-2.0 © Roman Malitskyi
|
|
224
|
+
|
|
225
|
+
Built-in icons are [Lucide](https://lucide.dev) glyphs, inlined so the package keeps zero runtime
|
|
226
|
+
dependencies. Lucide is ISC licensed; portions are held by Cole Bemis 2013–2022 as part of
|
|
227
|
+
Feather (MIT), all others by Lucide Contributors 2022 — full notice in
|
|
228
|
+
`src/lib/shared/icons.ts`.
|