@konce-pt/angular 0.8.2 → 0.8.5
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/CHANGELOG.md +406 -0
- package/README.md +5 -0
- package/chat/src/lib/llms.txt +160 -0
- package/fesm2022/konce-pt-angular-chat.mjs +1270 -0
- package/fesm2022/konce-pt-angular-chat.mjs.map +1 -0
- package/fesm2022/konce-pt-angular.mjs +1755 -398
- package/fesm2022/konce-pt-angular.mjs.map +1 -1
- package/package.json +15 -8
- package/src/lib/backdrop/llms.txt +163 -0
- package/src/lib/chip/llms.txt +8 -0
- package/src/lib/data-view/llms.txt +18 -2
- package/src/lib/icon-button/llms.txt +1 -0
- package/src/lib/mention/llms.txt +60 -0
- package/src/lib/order-list/llms.txt +13 -2
- package/src/lib/peek/llms.txt +45 -0
- package/src/lib/pick-list/llms.txt +18 -2
- package/src/lib/rich-text/llms.txt +15 -0
- package/types/konce-pt-angular-chat.d.ts +334 -0
- package/types/konce-pt-angular-chat.d.ts.map +1 -0
- package/types/konce-pt-angular.d.ts +454 -18
- package/types/konce-pt-angular.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konce-pt/angular",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "Open-source Angular 22 component library on Signals & Signal Forms — 70+ components, rich data table, zoneless, fully tokenized. Selektory kpt-*, klasy Kpt*.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "konce.pt",
|
|
@@ -46,13 +46,16 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"tslib": "^2.3.0",
|
|
49
|
-
"@konce-pt/
|
|
50
|
-
"@konce-pt/
|
|
51
|
-
"@konce-pt/
|
|
52
|
-
"@konce-pt/
|
|
53
|
-
"@konce-pt/map": "0.8.
|
|
54
|
-
"@konce-pt/
|
|
55
|
-
"@konce-pt/
|
|
49
|
+
"@konce-pt/chart": "0.8.5",
|
|
50
|
+
"@konce-pt/backdrop": "0.8.5",
|
|
51
|
+
"@konce-pt/datetime": "0.8.5",
|
|
52
|
+
"@konce-pt/chat": "0.8.5",
|
|
53
|
+
"@konce-pt/map": "0.8.5",
|
|
54
|
+
"@konce-pt/i18n": "0.8.5",
|
|
55
|
+
"@konce-pt/mention": "0.8.5",
|
|
56
|
+
"@konce-pt/table": "0.8.5",
|
|
57
|
+
"@konce-pt/roadmap": "0.8.5",
|
|
58
|
+
"@konce-pt/icons": "0.8.5"
|
|
56
59
|
},
|
|
57
60
|
"module": "fesm2022/konce-pt-angular.mjs",
|
|
58
61
|
"typings": "types/konce-pt-angular.d.ts",
|
|
@@ -68,6 +71,10 @@
|
|
|
68
71
|
"types": "./types/konce-pt-angular-charts.d.ts",
|
|
69
72
|
"default": "./fesm2022/konce-pt-angular-charts.mjs"
|
|
70
73
|
},
|
|
74
|
+
"./chat": {
|
|
75
|
+
"types": "./types/konce-pt-angular-chat.d.ts",
|
|
76
|
+
"default": "./fesm2022/konce-pt-angular-chat.mjs"
|
|
77
|
+
},
|
|
71
78
|
"./grid": {
|
|
72
79
|
"types": "./types/konce-pt-angular-grid.d.ts",
|
|
73
80
|
"default": "./fesm2022/konce-pt-angular-grid.mjs"
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# KptBackdrop (kpt-backdrop)
|
|
2
|
+
|
|
3
|
+
A decorative background layer for a section: the component wraps your content and paints an
|
|
4
|
+
animated canvas beneath it. You reach for it where a flat surface looks unfinished, and where
|
|
5
|
+
a video or a large image would cost bandwidth and refuse to follow the theme.
|
|
6
|
+
Projected content sits a layer above the canvas and behaves normally.
|
|
7
|
+
Import: `import { KptBackdrop } from '@konce-pt/angular';`
|
|
8
|
+
|
|
9
|
+
## Inputs (shared)
|
|
10
|
+
- `effect`: 'signal-grid' | 'wave' (default 'signal-grid') — the effect to draw
|
|
11
|
+
- `background`: string — the section background; empty takes `--kpt-color-surface`
|
|
12
|
+
- `speed`: number (default 1) — 1 is the calm pace of either effect, 0 freezes the picture
|
|
13
|
+
- `seed`: number (default 0) — the same value gives the same layout and the same sway
|
|
14
|
+
- `paused`: boolean — stops the animation, leaving the last frame
|
|
15
|
+
- `adaptive`: boolean — carries hardcoded colours onto the current theme's surface
|
|
16
|
+
|
|
17
|
+
## Inputs (signal-grid)
|
|
18
|
+
- `color`: string — the square colour, any CSS notation, tokens included; empty takes
|
|
19
|
+
`--kpt-color-primary`
|
|
20
|
+
- `anchor`: 'left' | 'right' (default 'right') — the edge the grid is densest at
|
|
21
|
+
- `cell`: number (default 5) — the square's side in px
|
|
22
|
+
- `gap`: number (default 11) — the space between squares in px
|
|
23
|
+
- `density`: number (default 0.8) — the share of lit cells at the anchor, 0–1
|
|
24
|
+
- `falloff`: number (default 1.4) — how fast the grid fades towards the far edge
|
|
25
|
+
|
|
26
|
+
## Inputs (wave)
|
|
27
|
+
- `colors`: string[] — the colour ramp the current slides along, closed into a loop; every
|
|
28
|
+
stop takes any CSS notation, `color`'s rules exactly
|
|
29
|
+
- `rotation`: number (default 12) — the angle the current crosses the frame at, in degrees
|
|
30
|
+
- `band`: number (default 0.34) — the band's width as a fraction of the frame's height
|
|
31
|
+
- `amplitude`: number (default 0.16) — how far the centre line sways
|
|
32
|
+
|
|
33
|
+
An input that does not belong to the current effect is simply not read.
|
|
34
|
+
|
|
35
|
+
## Methods
|
|
36
|
+
- `reseed()` — a fresh run of the effect at the same size and the same inputs
|
|
37
|
+
|
|
38
|
+
## Example
|
|
39
|
+
<kpt-backdrop effect="wave" [rotation]="18" [colors]="['#5B8AF2', '#A86DF2', '#F25B9E']">
|
|
40
|
+
<h1>Build your app from the first prompt</h1>
|
|
41
|
+
<kpt-button>Get started</kpt-button>
|
|
42
|
+
</kpt-backdrop>
|
|
43
|
+
|
|
44
|
+
## signal-grid
|
|
45
|
+
A fine grid of squares that quietly twinkle, dense at one edge and fading to empty at the other.
|
|
46
|
+
The gradient comes from **how many** squares are lit, not from opacity laid over an even grid —
|
|
47
|
+
that is why it reads as a signal rather than as a texture with a mask on top.
|
|
48
|
+
|
|
49
|
+
Each cell derives its own draws — whether it is lit, its twinkle phase and its rate — from its own
|
|
50
|
+
column and row, so the layout survives a resize instead of reshuffling. The rates are spread over
|
|
51
|
+
0.45–1.55, because at one shared rate the whole grid pulses in unison and the effect turns into
|
|
52
|
+
breathing. The grid deliberately runs past the area and the overflow is clipped: a grid that stops
|
|
53
|
+
before the edge looks cut off.
|
|
54
|
+
|
|
55
|
+
## wave
|
|
56
|
+
One soft current of light flowing across the frame, with hues sliding along it and no hard edge
|
|
57
|
+
anywhere. The centre line is a sum of harmonics at incommensurable frequencies, so the current
|
|
58
|
+
sways without a repeating pattern; brightness falls away from it on a Gaussian curve.
|
|
59
|
+
|
|
60
|
+
`rotation` turns the whole current: 0 runs it horizontally, 90 stands it on end. `band` sets how
|
|
61
|
+
wide it is, `amplitude` how much it sways — set `amplitude` to 0 and the shape stands still while
|
|
62
|
+
the colours keep flowing.
|
|
63
|
+
|
|
64
|
+
The ramp is closed into a loop, so the last colour returns to the first; a ramp with a seam would
|
|
65
|
+
show it in the middle of the frame. Colours are mixed on the polar form of OKLab, going round the
|
|
66
|
+
circle rather than across it: a straight mix of opposite hues crosses the achromatic axis and the
|
|
67
|
+
current goes grey exactly where it is brightest.
|
|
68
|
+
|
|
69
|
+
Without `colors` the ramp is `--kpt-color-primary` plus two hues derived from it by rotation.
|
|
70
|
+
The library's palette is neutral, so that default current is single-hued and muted — the hue
|
|
71
|
+
sliding only shows once you give it a real ramp.
|
|
72
|
+
|
|
73
|
+
Every stop is put to the browser, so `oklch()`, `color-mix()`, `rgb()` and named colours are read
|
|
74
|
+
the same as hex; alpha is dropped. A stop the browser refuses falls out of the ramp, and if every
|
|
75
|
+
one of them falls out the default ramp takes over rather than the section going blank — a dev
|
|
76
|
+
build says in the console which stops it dropped.
|
|
77
|
+
|
|
78
|
+
## What it costs
|
|
79
|
+
`wave` is computed in a buffer whose longer side is 160 px and scaled up: softness comes from the
|
|
80
|
+
browser's interpolation, so a few thousand pixels a frame cover a frame of any size. It is not
|
|
81
|
+
drawn at full canvas resolution.
|
|
82
|
+
|
|
83
|
+
## Where the maths lives
|
|
84
|
+
The grid layout, the density ramp, the twinkle, the current and the colour ramp — plus the
|
|
85
|
+
renderers for both effects — live in `@konce-pt/backdrop`, plain TypeScript with its own
|
|
86
|
+
`node --test` suite, shared by both ports. The component is the lifecycle around them.
|
|
87
|
+
|
|
88
|
+
## Rest
|
|
89
|
+
Drawing stops when there is nothing to watch: the section is off-screen (`IntersectionObserver`),
|
|
90
|
+
the tab is in the background, `paused` is set, `speed` is 0, or the system asks for reduced motion
|
|
91
|
+
(`prefers-reduced-motion`). What is left is a single static frame, not emptiness — the effect is
|
|
92
|
+
part of the composition, not decoration.
|
|
93
|
+
|
|
94
|
+
`speed` feeds the clock rather than the phase, so moving a speed slider accelerates the picture
|
|
95
|
+
instead of jumping it.
|
|
96
|
+
|
|
97
|
+
## Accessibility
|
|
98
|
+
The canvas carries `aria-hidden="true"` and `pointer-events: none` — it is decoration with no
|
|
99
|
+
content and nothing to hit. Content keeps its own roles and tab order. Under reduced motion the
|
|
100
|
+
animation does not start at all.
|
|
101
|
+
|
|
102
|
+
## Tokens
|
|
103
|
+
`--kpt-color-primary` (squares and the default ramp), `--kpt-color-surface` (background),
|
|
104
|
+
`--kpt-color-on-surface`. Overrides for a whole section without touching the inputs:
|
|
105
|
+
`--kpt-backdrop-color`, `--kpt-backdrop-surface`.
|
|
106
|
+
|
|
107
|
+
## Adaptive colours
|
|
108
|
+
A literal stays put by design, which is right for a brand colour and wrong for a section meant to
|
|
109
|
+
read in both themes. `adaptive` closes that gap: it carries `color`, `colors` and `background`
|
|
110
|
+
onto the surface of the current theme, keeping each one's distance from that surface. Black picked
|
|
111
|
+
for a white section comes out white on a near-black ground, and that white background comes out at
|
|
112
|
+
the surface's own lightness. Only lightness moves — hue and chroma stay, so a brand colour keeps
|
|
113
|
+
being that colour and only changes how light it is.
|
|
114
|
+
|
|
115
|
+
It touches literals only. An empty input takes a token, and a value reaching through `var()`
|
|
116
|
+
reaches a token too; both already follow the theme, and adapting them would turn them back again.
|
|
117
|
+
Values written for the light theme are the assumption — the library keeps light in `:root` and
|
|
118
|
+
dark as the override.
|
|
119
|
+
|
|
120
|
+
## Content on a custom background
|
|
121
|
+
The host paints `--kpt-color-surface` and lets content inherit `--kpt-color-on-surface`, which is
|
|
122
|
+
right until the section gets a `background` of its own — then that token describes the page around
|
|
123
|
+
it, not the ground the content actually sits on. A dark section in a light theme would come out
|
|
124
|
+
black on black.
|
|
125
|
+
|
|
126
|
+
So a section with its own background works out its own ink: the host sets `color` to match what it
|
|
127
|
+
paints, and announces the result as `data-tone` (`light` for a light background, `dark` for a dark
|
|
128
|
+
one). Text follows by inheritance; anything needing more than a text colour — buttons in the
|
|
129
|
+
section, say — can hang its own tokens off the attribute:
|
|
130
|
+
|
|
131
|
+
:where(kpt-backdrop[data-tone='light']) .hero { --kpt-button-filled-bg: #15181a; }
|
|
132
|
+
|
|
133
|
+
The tone is computed from the background the section really paints, so with `adaptive` on it
|
|
134
|
+
matches the adapted value, not the one written in the template. A section without its own
|
|
135
|
+
background announces nothing and content stays on `--kpt-color-on-surface`.
|
|
136
|
+
|
|
137
|
+
## Theme
|
|
138
|
+
Canvas does not expand `var()`, so the colour is read once and baked into the renderer — the
|
|
139
|
+
component therefore watches for anything that can restyle the tokens under it and reads them
|
|
140
|
+
again. `[data-theme="dark"]` is not tied to `:root`, so the watch covers `data-theme`, `class`
|
|
141
|
+
and `style` on every ancestor from the host up to `<html>`, plus the `prefers-color-scheme` query
|
|
142
|
+
for an application that keeps its dark tokens in a media query. A runtime override of
|
|
143
|
+
`--kpt-color-primary` is picked up the same way as a theme switch. The renderer is rebuilt only
|
|
144
|
+
when the colour actually came out different, so an unrelated class landing on `<html>` costs one
|
|
145
|
+
cheap read and nothing else.
|
|
146
|
+
|
|
147
|
+
Whether an explicit `color` or `colors` follows the theme is up to how it is written. A literal
|
|
148
|
+
stays put — `#5b8af2` is `#5b8af2` in either theme, which is what someone spelling out a brand
|
|
149
|
+
colour wants. An expression reaching for a token is resolved against the tree on every rebuild, so
|
|
150
|
+
it moves with the theme on its own:
|
|
151
|
+
|
|
152
|
+
<kpt-backdrop color="color-mix(in oklab, #5b8af2, var(--kpt-color-surface) 30%)">
|
|
153
|
+
|
|
154
|
+
`var(--kpt-color-primary)` works the same way. A name that resolves to nothing falls back to the
|
|
155
|
+
token for `color`, and drops out of the ramp for `colors`.
|
|
156
|
+
|
|
157
|
+
## Contrast
|
|
158
|
+
The palette is neutral, so `--kpt-color-primary` is near-black on a light surface and near-white
|
|
159
|
+
on a dark one — at the default density the picture is strong, and text laid over the dense half
|
|
160
|
+
loses its reading. Keep the copy on the side the grid fades towards (that is what `anchor` is
|
|
161
|
+
for), or drop `density`. `wave` is brightest along its centre line, so the same rule applies
|
|
162
|
+
through `rotation` and `band`. On a custom `background` give the colours a muted shade:
|
|
163
|
+
a full-strength colour behind text costs the reading, not the effect.
|
package/src/lib/chip/llms.txt
CHANGED
|
@@ -4,11 +4,19 @@ A chip / tag — a label, optionally removable. Import: `import { KptChip } from
|
|
|
4
4
|
|
|
5
5
|
## Inputs / outputs
|
|
6
6
|
- `variant`: 'neutral'|'primary'|'success'|'danger'|'warning'|'info'
|
|
7
|
+
- `textTransform`: 'none'|'capitalize'|'uppercase'|'lowercase' (default 'none') — the label's letter case
|
|
7
8
|
- `removable`: boolean (a × button); `disabled`: boolean; `removed`: output<void>
|
|
8
9
|
|
|
9
10
|
## Examples
|
|
10
11
|
<kpt-chip>Angular</kpt-chip>
|
|
11
12
|
<kpt-chip variant="success" removable (removed)="onRemove()">UI</kpt-chip>
|
|
13
|
+
<kpt-chip textTransform="capitalize">new · starter kit</kpt-chip>
|
|
14
|
+
|
|
15
|
+
## Letter case
|
|
16
|
+
`textTransform` sets `text-transform` on the chip, so the label can stay in the application's own
|
|
17
|
+
wording while the chip decides how it is displayed. `capitalize` raises the first letter of every
|
|
18
|
+
word — **including after a hyphen** ("Agent-Ready"), because CSS does not know where a compound
|
|
19
|
+
word ends. For labels with a hyphen, spelling it out in the content is the exact route.
|
|
12
20
|
|
|
13
21
|
## Tokens
|
|
14
22
|
A color-mix background over the variant, `--kpt-color-muted` (neutral).
|
|
@@ -7,12 +7,28 @@ Import: `import { KptDataView } from '@konce-pt/angular';`
|
|
|
7
7
|
## Inputs / model
|
|
8
8
|
- `items`: T[]
|
|
9
9
|
- `layout`: model<'list' | 'grid'> (the toggle in the bar)
|
|
10
|
-
- `pageSize`: number (0 = no pagination)
|
|
10
|
+
- `pageSize`: model<number> (0 = no pagination) — two-way, because the paginator's select writes to it
|
|
11
|
+
- `pageSizeOptions`: number[] (empty = the select offers the current size only)
|
|
12
|
+
- `gridColumns`: model<number> (0 = as many as fit) — two-way, the density bar writes to it
|
|
13
|
+
- `gridColumnsOptions`: number[] (fewer than two = no density bar)
|
|
14
|
+
- `gridMinWidth`: string (default `10rem`) — the narrowest card worth rendering
|
|
15
|
+
- `paginated`: boolean
|
|
11
16
|
|
|
12
17
|
## Example
|
|
13
|
-
<kpt-data-view [items]="products" [pageSize]="6">
|
|
18
|
+
<kpt-data-view [items]="products" [(pageSize)]="size" [pageSizeOptions]="[3, 6, 9]">
|
|
14
19
|
<ng-template let-p><div>{{ p.name }}</div></ng-template>
|
|
15
20
|
</kpt-data-view>
|
|
16
21
|
|
|
22
|
+
## The column count is a ceiling
|
|
23
|
+
`gridColumns` caps the grid, it does not pin it: the track minimum grows to the width of one of
|
|
24
|
+
N columns, so a narrow container drops to two or one column instead of squeezing cards below
|
|
25
|
+
`gridMinWidth`. Set `gridColumns` to one of `gridColumnsOptions` — with a value outside the list
|
|
26
|
+
no density button reads as active.
|
|
27
|
+
|
|
28
|
+
## The pager stays while there is a choice
|
|
29
|
+
It shows up when the items outgrow one page, and also when `pageSizeOptions` holds more than one
|
|
30
|
+
size. Otherwise picking the largest size would hide the very select that was just used, with no
|
|
31
|
+
way back to a smaller one.
|
|
32
|
+
|
|
17
33
|
## Tokens
|
|
18
34
|
Item cards `--kpt-color-surface-raised`; the toggle `--kpt-color-primary`.
|
|
@@ -7,6 +7,7 @@ Import: `import { KptIconButton } from '@konce-pt/angular';`
|
|
|
7
7
|
- `variant`: 'filled'|'tonal'|'outline'|'text'|'danger'; `size`: 'sm'|'md'|'lg'; `shape`: 'round'|'square'
|
|
8
8
|
- `type`, `disabled`, `loading`, `ariaLabel` (required)
|
|
9
9
|
- `ariaPressed`: `boolean | null` = `null` — toggle state; lands on the inner `<button>`, so a screen reader announces it (`[attr.aria-pressed]` on the tag would sit on the host, which has no button role)
|
|
10
|
+
- `ariaExpanded`: `boolean | null` = `null` — disclosure state for a button that opens a panel; lands on the inner `<button>` for the same reason
|
|
10
11
|
|
|
11
12
|
## Examples
|
|
12
13
|
<kpt-icon-button ariaLabel="Settings"><kpt-icon name="menu" /></kpt-icon-button>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# KptMention (kpt-mention) / KptMentions (kpt-mentions)
|
|
2
|
+
|
|
3
|
+
Mentions in text: `@someone` as an element you can hover to see a peek card with the rest of the
|
|
4
|
+
connections. `kpt-mention` is a single mention; `kpt-mentions` turns a whole paragraph into text
|
|
5
|
+
plus mentions.
|
|
6
|
+
Requires `import '@angular/cdk/overlay-prebuilt.css';` (the card runs on `kpt-peek`)
|
|
7
|
+
Import: `import { KptMention, KptMentions } from '@konce-pt/angular';`
|
|
8
|
+
|
|
9
|
+
## KptMention — inputs
|
|
10
|
+
- `item`: `KptMentionItem` — the whole entry at once; the single inputs below win over it
|
|
11
|
+
- `id`, `label`, `kind`: string — `kind` lands in `data-kind`, so it can be styled per type
|
|
12
|
+
- `prefix`: string (default '@') — an empty string leaves the bare name
|
|
13
|
+
- `href`: string | null — with it the mention is a link, without it a button opening the card
|
|
14
|
+
- `placement`, `openDelay` — passed to `kpt-peek`
|
|
15
|
+
- `disabled`: boolean — no card; the mention stays a plain highlighted word
|
|
16
|
+
- projected content = the card
|
|
17
|
+
|
|
18
|
+
## KptMentions — inputs
|
|
19
|
+
- `text`: string — the content with `@id` or `@[Name with spaces](id)`
|
|
20
|
+
- `items`: `readonly KptMentionItem[]` — entries the ids resolve against
|
|
21
|
+
- `prefix`, `placement` — passed to every mention
|
|
22
|
+
- an `<ng-template>` inside = the card; its context is the item as `$implicit` plus `id` and `label`
|
|
23
|
+
|
|
24
|
+
## Example
|
|
25
|
+
<kpt-mentions [text]="note" [items]="people">
|
|
26
|
+
<ng-template let-item let-label="label">
|
|
27
|
+
<kpt-card>{{ item?.data?.role ?? label }}</kpt-card>
|
|
28
|
+
</ng-template>
|
|
29
|
+
</kpt-mentions>
|
|
30
|
+
|
|
31
|
+
## The text stays text
|
|
32
|
+
`kpt-mentions` does not render HTML: the paragraph goes in as a plain string, `parseMentionText()`
|
|
33
|
+
from `@konce-pt/mention` splits it into segments and the mention is an element the library builds
|
|
34
|
+
itself. An application does not have to push user-written content through a sanitizer to get
|
|
35
|
+
mentions out of it.
|
|
36
|
+
|
|
37
|
+
An id that is not on the list still renders — the label falls back to the id, because a note has to
|
|
38
|
+
stay readable after someone leaves the team. Without a card template the mention is a highlighted
|
|
39
|
+
word, not a button: there is nothing to open, so it does not pretend otherwise.
|
|
40
|
+
|
|
41
|
+
## The id is what is stored
|
|
42
|
+
`id` survives a rename, the label does not — that is why the text carries the id and the name comes
|
|
43
|
+
from `items`. `@[Anna Kowalska](anna.k)` is the only way to write a name with spaces, and even then
|
|
44
|
+
the list wins over the label written into the text: data is usually fresher than a note from last
|
|
45
|
+
month.
|
|
46
|
+
|
|
47
|
+
## Mentions in the editor
|
|
48
|
+
`kpt-rich-text` has `mentions`, `mentionLimit` and `(mentioned)`: typing `@` opens the suggestion
|
|
49
|
+
list, arrows and Enter (or Tab) insert the mention as
|
|
50
|
+
`<span class="kpt-mention" data-mention="id" contenteditable="false">`. The id survives saving,
|
|
51
|
+
and `contenteditable="false"` keeps the mention in one piece — without it the caret would walk into
|
|
52
|
+
the middle of a surname.
|
|
53
|
+
|
|
54
|
+
## Tokens
|
|
55
|
+
The mention is underlined with a **dotted** line: `--kpt-color-primary-border` at rest, darkening
|
|
56
|
+
to `--kpt-color-primary` on hover and while the card is open. Dotted, not solid — a solid underline
|
|
57
|
+
would read as a link, and a mention usually leads nowhere, it opens a card. Text
|
|
58
|
+
`--kpt-color-primary`; a mention without a card `--kpt-color-text` + `--kpt-font-weight-medium` and
|
|
59
|
+
no line at all, since there is nothing to promise. Focus ring `--kpt-color-focus-ring`. The card
|
|
60
|
+
takes its own tokens from `kpt-peek`.
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# KptOrderList (kpt-order-list)
|
|
2
2
|
|
|
3
|
-
A list with manual reordering (up/down). Select an item and move it with the buttons
|
|
3
|
+
A list with manual reordering (up/down). Select an item and move it with the buttons, or turn on
|
|
4
|
+
`dragdrop` and drag it into place.
|
|
4
5
|
The item template comes through projection: `<ng-template let-item>`.
|
|
5
6
|
Import: `import { KptOrderList } from '@konce-pt/angular';`
|
|
6
7
|
|
|
7
8
|
## Inputs / model
|
|
8
9
|
- `items`: model<T[]> (two-way — returns the new order)
|
|
9
10
|
- `header`: string
|
|
11
|
+
- `dragdrop`: boolean, default false — enables dragging (opt-in, nothing changes without it)
|
|
10
12
|
|
|
11
13
|
## Example
|
|
12
|
-
<kpt-order-list [(items)]="tasks" header="Order">
|
|
14
|
+
<kpt-order-list [(items)]="tasks" header="Order" dragdrop>
|
|
13
15
|
<ng-template let-item>{{ item.name }}</ng-template>
|
|
14
16
|
</kpt-order-list>
|
|
15
17
|
|
|
18
|
+
## Where a dragged item lands
|
|
19
|
+
Dropping onto a row puts the dragged item at that row's position and everything else shifts, while
|
|
20
|
+
the buttons keep swapping with the neighbour. Dropping on the empty part of the list appends at the
|
|
21
|
+
end. Either way the selection follows the item, so the next button press moves the same entry.
|
|
22
|
+
|
|
16
23
|
## Tokens
|
|
17
24
|
Selection `--kpt-color-primary`; buttons `--kpt-color-surface-raised`.
|
|
25
|
+
|
|
26
|
+
## Accessibility
|
|
27
|
+
Native HTML5 drag and drop has no keyboard equivalent, so the up/down buttons stay the full keyboard
|
|
28
|
+
path — `dragdrop` adds to them, it never replaces them.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# KptPeek (kpt-peek)
|
|
2
|
+
|
|
3
|
+
A peek card — content tied to what you are looking at, shown without leaving the text. Hover opens
|
|
4
|
+
it, the card itself is interactive (links, buttons), and a click pins it.
|
|
5
|
+
Requires `import '@angular/cdk/overlay-prebuilt.css';`
|
|
6
|
+
Import: `import { KptPeek, KptPeekTrigger } from '@konce-pt/angular';`
|
|
7
|
+
|
|
8
|
+
## Slots
|
|
9
|
+
- the element carrying the `kptPeekTrigger` attribute = the trigger; everything else = the card
|
|
10
|
+
|
|
11
|
+
## Inputs / outputs
|
|
12
|
+
- `placement`: 'top' | 'bottom' (default 'bottom') — CDK flips it when there is no room
|
|
13
|
+
- `openDelay`: number (default 300) — the wait before hover opens the card
|
|
14
|
+
- `closeDelay`: number (default 200) — the wait before leaving the trigger closes it
|
|
15
|
+
- `disabled`: boolean — the card never opens; the trigger stays a plain link or button
|
|
16
|
+
- `label`: string — the card's accessible name; without it the trigger's text is used
|
|
17
|
+
- `(opened)`, `(closed)` → `void` — the moment to fetch the card's data
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
<kpt-peek>
|
|
21
|
+
<a kptPeekTrigger href="/people/anna">@Anna Kowalska</a>
|
|
22
|
+
<kpt-card>Profile, projects, contact…</kpt-card>
|
|
23
|
+
</kpt-peek>
|
|
24
|
+
|
|
25
|
+
## Which of the three
|
|
26
|
+
`kptTooltip` carries plain text and cannot be clicked (`pointer-events: none`), so a link inside it
|
|
27
|
+
is unreachable. `kpt-popover` opens on click and puts a backdrop over the page, so it is a small
|
|
28
|
+
modal. `kpt-peek` sits between them: it opens on hover, the card is interactive, and nothing is
|
|
29
|
+
covered.
|
|
30
|
+
|
|
31
|
+
## Hover is not the only way in
|
|
32
|
+
Hover opens after `openDelay` and leaving closes after `closeDelay` — the pointer needs time to
|
|
33
|
+
travel from the trigger to the card, so entering the card cancels the close. Focus opens it with no
|
|
34
|
+
delay (a keyboard does not sweep across elements by accident). A click, Enter or a tap **pins** the
|
|
35
|
+
card: it stays after the pointer leaves and focus moves inside it. That is the only route to the
|
|
36
|
+
card's content where there is no hover at all, so interactive content stays reachable on touch and
|
|
37
|
+
from the keyboard. Escape closes it and hands focus back to the trigger; so does a click outside.
|
|
38
|
+
|
|
39
|
+
## Accessibility
|
|
40
|
+
The trigger keeps its own role (a link stays a link) and carries `aria-expanded` plus
|
|
41
|
+
`aria-controls` while the card is open. The card is `role="dialog"` with a name from `label` or
|
|
42
|
+
the trigger's text. It is not a focus trap — the card is not modal and the page stays usable.
|
|
43
|
+
|
|
44
|
+
## Tokens
|
|
45
|
+
`--kpt-color-surface-raised`, `--kpt-color-border`, `--kpt-elevation-3`, `--kpt-color-focus-ring`.
|
|
@@ -1,17 +1,33 @@
|
|
|
1
1
|
# KptPickList (kpt-pick-list)
|
|
2
2
|
|
|
3
|
-
Transfers items between two lists (source and target). Select and move them (one at a time or all)
|
|
3
|
+
Transfers items between two lists (source and target). Select and move them (one at a time or all),
|
|
4
|
+
double-click a row to send it across, or turn on `dragdrop` and drag it.
|
|
4
5
|
The item template comes through projection: `<ng-template let-item>`.
|
|
5
6
|
Import: `import { KptPickList } from '@konce-pt/angular';`
|
|
6
7
|
|
|
7
8
|
## Inputs / model
|
|
8
9
|
- `source`: model<T[]>; `target`: model<T[]> (both two-way)
|
|
9
10
|
- `sourceHeader`/`targetHeader`: string
|
|
11
|
+
- `dragdrop`: boolean, default false — enables dragging (opt-in, nothing changes without it)
|
|
10
12
|
|
|
11
13
|
## Example
|
|
12
|
-
<kpt-pick-list [(source)]="available" [(target)]="selected" sourceHeader="Available" targetHeader="Selected">
|
|
14
|
+
<kpt-pick-list [(source)]="available" [(target)]="selected" sourceHeader="Available" targetHeader="Selected" dragdrop>
|
|
13
15
|
<ng-template let-item>{{ item.name }}</ng-template>
|
|
14
16
|
</kpt-pick-list>
|
|
15
17
|
|
|
18
|
+
## A double-click moves one item
|
|
19
|
+
It sends exactly the row you clicked to the other panel and appends it at the end, whatever else is
|
|
20
|
+
selected. It does not need `dragdrop` — the two clicks underneath cancel each other out, so the rest
|
|
21
|
+
of the selection is left alone.
|
|
22
|
+
|
|
23
|
+
## Where a dragged item lands
|
|
24
|
+
Dropping onto a row puts the dragged item at that row's position: inside one panel that reorders,
|
|
25
|
+
across panels it transfers. Dropping on the empty part of a panel appends at the end. An item that
|
|
26
|
+
leaves a panel also leaves that panel's selection.
|
|
27
|
+
|
|
16
28
|
## Tokens
|
|
17
29
|
Selection `--kpt-color-primary`; headers `--kpt-color-surface-variant`.
|
|
30
|
+
|
|
31
|
+
## Accessibility
|
|
32
|
+
Native HTML5 drag and drop has no keyboard equivalent, so the four move buttons stay the full
|
|
33
|
+
keyboard path — `dragdrop` adds to them, it never replaces them.
|
|
@@ -12,6 +12,21 @@ Import: `import { KptRichText, KptRichTool, KptRichToolbar } from '@konce-pt/ang
|
|
|
12
12
|
- `placeholder`: string; `disabled`/`invalid`/`touched`: boolean; `touch`: output
|
|
13
13
|
- `maxListLevel`: number = 6 — the maximum list nesting depth. The limit applies to interaction
|
|
14
14
|
(Tab and the `indent`/`outdent` tools); pasted content is not flattened, so that no data is lost.
|
|
15
|
+
- `mentions`: `readonly KptMentionItem[]` — suggestions for `@`; an empty list turns the mechanism
|
|
16
|
+
off, so `@` stays an ordinary character. `mentionLimit`: number = 8; `(mentioned)` fires with the
|
|
17
|
+
inserted entry — the moment to notify a person or attach a link.
|
|
18
|
+
|
|
19
|
+
## Mentions (`@`)
|
|
20
|
+
With `mentions` set, typing `@` opens a suggestion list anchored at the caret: arrows move through
|
|
21
|
+
it, Enter or Tab inserts, Escape closes. The query is read from the **text node** at the caret, not
|
|
22
|
+
from the HTML, and recognised by `mentionQuery()` from `@konce-pt/mention` — the same rules as in a
|
|
23
|
+
plain text field.
|
|
24
|
+
|
|
25
|
+
An inserted mention is `<span class="kpt-mention" data-mention="id" contenteditable="false">@Name`
|
|
26
|
+
plus a non-breaking space. The id survives a rename and the round trip through the value;
|
|
27
|
+
`contenteditable="false"` keeps the mention in one piece, and the space is what gives the caret a
|
|
28
|
+
place to stand after a block it cannot enter. Both attributes are on the sanitizer's allowlist —
|
|
29
|
+
they are inert, so they open no new door.
|
|
15
30
|
|
|
16
31
|
## Tools (KptRichTool)
|
|
17
32
|
- Clipboard: `copy`, `paste` (with formatting, sanitized), `pasteText` (without formatting)
|