@rak200/ui 0.2.15 → 0.2.17
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/README.md +3 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/menu.d.ts +92 -0
- package/dist/menu.d.ts.map +1 -0
- package/dist/menu.js +597 -0
- package/dist/menu.js.map +1 -0
- package/dist/placement.d.ts +56 -0
- package/dist/placement.d.ts.map +1 -0
- package/dist/placement.js +60 -0
- package/dist/placement.js.map +1 -0
- package/dist/toast.d.ts +158 -0
- package/dist/toast.d.ts.map +1 -0
- package/dist/toast.js +494 -0
- package/dist/toast.js.map +1 -0
- package/dist/tokens.d.ts +1 -1
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +27 -0
- package/dist/tokens.js.map +1 -1
- package/dist/tooltip.d.ts +7 -3
- package/dist/tooltip.d.ts.map +1 -1
- package/dist/tooltip.js +15 -14
- package/dist/tooltip.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement.d.ts","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,gGAAgG;AAChG,MAAM,MAAM,IAAI,GAAG,aAAa,GAAG,WAAW,CAAC;AAE/C,sEAAsE;AACtE,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,cAAc,CAAC;AAE9C,6FAA6F;AAC7F,MAAM,WAAW,GAAG;IAChB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CAC3B;AAED,6EAA6E;AAC7E,MAAM,WAAW,SAAS;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAChC;AAOD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CACjB,MAAM,EAAE,GAAG,EACX,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC7D,MAAM,EAAE,IAAI,EACZ,KAAK,EAAE,KAAK,GACb,SAAS,CAuBX"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where an overlay lands, as arithmetic rather than as a rendering.
|
|
3
|
+
*
|
|
4
|
+
* **One answer to one problem, which is what issue #23 asked for.** `<ui-tooltip>` settled
|
|
5
|
+
* how this package places a `popover` — by hand, over the top layer, with CSS anchor
|
|
6
|
+
* positioning measured as present in this engine and deliberately declined; its docblock
|
|
7
|
+
* carries the whole argument. `<ui-menu>` needs the same thing pointing the other way, so
|
|
8
|
+
* the answer moved here rather than being written twice. A component with two placements is
|
|
9
|
+
* a component that is wrong in one of them.
|
|
10
|
+
*
|
|
11
|
+
* **Taken as numbers rather than as elements, and that is the floors talking** — the same
|
|
12
|
+
* reason `reservedGutter` in `src/dialog.ts` is handed two widths instead of a window. A
|
|
13
|
+
* function of four boxes is decided here and checked directly, at the edges that a rendered
|
|
14
|
+
* page can only reach by luck: an anchor with exactly the tip's height above it, a box wider
|
|
15
|
+
* than the viewport, a menu at the last pixel of the screen. The callers keep no branch of
|
|
16
|
+
* their own.
|
|
17
|
+
*
|
|
18
|
+
* Internal — not re-exported from `src/index.ts`, because what a consumer positions is their
|
|
19
|
+
* own element, and this is how two of ours find each other.
|
|
20
|
+
*/
|
|
21
|
+
/** The other one. A placement has two sides and flipping is what the second one is for. */
|
|
22
|
+
function opposite(side) {
|
|
23
|
+
return side === 'block-start' ? 'block-end' : 'block-start';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Puts `box` beside `anchor` on the side it asked for, on the other side when there is no
|
|
27
|
+
* room, and inside the viewport either way.
|
|
28
|
+
*
|
|
29
|
+
* @param anchor - The element being pointed at, in viewport coordinates.
|
|
30
|
+
* @param box - The overlay, measured **after** it is shown: its height depends on how its
|
|
31
|
+
* text wrapped at this width in this font, which no caller can know and none should guess.
|
|
32
|
+
* @param viewport - The visible area, scrollbar excluded — `document.documentElement`'s
|
|
33
|
+
* client size rather than `window.inner*`, so a reserved scrollbar is not counted as room.
|
|
34
|
+
* @param prefer - Where it goes when it fits. A tip goes above its trigger; a menu hangs
|
|
35
|
+
* below its button.
|
|
36
|
+
* @param align - `center` for something that points at the anchor, `inline-start` for
|
|
37
|
+
* something that hangs from it.
|
|
38
|
+
*/
|
|
39
|
+
export function place(anchor, box, viewport, prefer, align) {
|
|
40
|
+
const room = prefer === 'block-start' ? anchor.top : viewport.height - (anchor.top + anchor.height);
|
|
41
|
+
const side = room >= box.height ? prefer : opposite(prefer);
|
|
42
|
+
// Looked up by name rather than compared against one, and that is a measurement rather
|
|
43
|
+
// than a style: `align === 'center' ? … : anchor.left` sends every OTHER name down the
|
|
44
|
+
// same arm, so the caller that passes `inline-start` could pass anything at all — an
|
|
45
|
+
// empty string included — and this would compute the same number. Keyed by the name,
|
|
46
|
+
// each one reaches its own value and no other name reaches either.
|
|
47
|
+
const lined = {
|
|
48
|
+
center: anchor.left + anchor.width / 2 - box.width / 2,
|
|
49
|
+
'inline-start': anchor.left,
|
|
50
|
+
}[align];
|
|
51
|
+
return {
|
|
52
|
+
side,
|
|
53
|
+
blockStart: side === 'block-start' ? anchor.top - box.height : anchor.top + anchor.height,
|
|
54
|
+
// Lined up first, then pulled back inside — in that order, because a box centred on
|
|
55
|
+
// an anchor near the edge is a box half off the screen. `Math.max` last, so a box
|
|
56
|
+
// wider than the viewport starts at the leading edge rather than at a negative one.
|
|
57
|
+
inlineStart: Math.max(0, Math.min(lined, viewport.width - box.width)),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=placement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"placement.js","sourceRoot":"","sources":["../src/placement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAuBH,2FAA2F;AAC3F,SAAS,QAAQ,CAAC,IAAU;IACxB,OAAO,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CACjB,MAAW,EACX,GAAQ,EACR,QAA6D,EAC7D,MAAY,EACZ,KAAY;IAEZ,MAAM,IAAI,GACN,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE5D,uFAAuF;IACvF,uFAAuF;IACvF,qFAAqF;IACrF,qFAAqF;IACrF,mEAAmE;IACnE,MAAM,KAAK,GAAG;QACV,MAAM,EAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC;QACtD,cAAc,EAAE,MAAM,CAAC,IAAI;KAC9B,CAAC,KAAK,CAAC,CAAC;IAET,OAAO;QACH,IAAI;QACJ,UAAU,EAAE,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,MAAM;QACzF,oFAAoF;QACpF,kFAAkF;QAClF,oFAAoF;QACpF,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;KACxE,CAAC;AACN,CAAC"}
|
package/dist/toast.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { LitElement, type TemplateResult } from 'lit';
|
|
2
|
+
/** What a toast is telling the reader, which decides how it looks *and* how it is announced. */
|
|
3
|
+
export type ToastVariant = 'info' | 'success' | 'warning' | 'danger';
|
|
4
|
+
/**
|
|
5
|
+
* The live regions a toast is announced through, and the box the stack is drawn in.
|
|
6
|
+
*
|
|
7
|
+
* **One container, two regions, and the count is the number of politenesses rather than
|
|
8
|
+
* the number of messages.** A live region has to be in the document *before* the text is
|
|
9
|
+
* put into it — a region that arrives with its content already inside is the single most
|
|
10
|
+
* common way a toast is never announced — so the regions are rendered on connection and
|
|
11
|
+
* never removed, and a toast is added to whichever one its variant names.
|
|
12
|
+
*
|
|
13
|
+
* That is the whole reason there are two. `aria-live` cannot vary per message inside one
|
|
14
|
+
* region, and giving each toast its own `aria-live` would make every message its own
|
|
15
|
+
* region root, which is the shape this component exists to avoid. Two regions that outlive
|
|
16
|
+
* every message answer *politeness is per toast* without ever creating one.
|
|
17
|
+
*
|
|
18
|
+
* **Neither region carries `role="alert"` or `role="status"`**, and that is not a shortcut.
|
|
19
|
+
* Both roles imply `aria-atomic="true"`, so every arrival re-announces the whole stack —
|
|
20
|
+
* three toasts up means the third one reads all three. `aria-live` alone leaves
|
|
21
|
+
* `aria-atomic` at its `false` default, which announces the toast that arrived and nothing
|
|
22
|
+
* else. The semantics of `role="alert"` are `aria-live="assertive"` plus that atomicity;
|
|
23
|
+
* this keeps the half that is right for a stack.
|
|
24
|
+
*
|
|
25
|
+
* ## Where it sits
|
|
26
|
+
*
|
|
27
|
+
* A `popover`, for the reason `<ui-tooltip>` is one: the top layer escapes every stacking
|
|
28
|
+
* context and every `overflow: hidden` above it, so this package still names no `z-index`
|
|
29
|
+
* and opens no layering category — the third overlay in a row not to. `manual`, because an
|
|
30
|
+
* `auto` popover light-dismisses, and a toast that vanished on the next click somewhere
|
|
31
|
+
* else would be a notice the user never read.
|
|
32
|
+
*
|
|
33
|
+
* It is shown once, on connection, and never hidden — which costs the one thing promotion
|
|
34
|
+
* would have bought. A modal `<dialog>` opened *after* the toaster connects sits above it
|
|
35
|
+
* in the top layer, and re-promoting the stack per message would fix that ordering and
|
|
36
|
+
* break the announcement, by taking the region out of the tree and putting it back with
|
|
37
|
+
* content already in it. The trade is not close, and it is not the real limit anyway: a
|
|
38
|
+
* modal makes the rest of the document **inert**, so a toaster outside an open modal is out
|
|
39
|
+
* of the accessibility tree whichever layer it is in. `docs/toast.md` says where to put one
|
|
40
|
+
* for a page that toasts from inside a dialog.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```html
|
|
44
|
+
* <ui-toaster></ui-toaster>
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare class UiToaster extends LitElement {
|
|
48
|
+
static readonly styles: import("lit").CSSResult;
|
|
49
|
+
connectedCallback(): void;
|
|
50
|
+
render(): TemplateResult;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* One message in a {@link UiToaster}.
|
|
54
|
+
*
|
|
55
|
+
* ## The variant decides three things, and that is the design
|
|
56
|
+
*
|
|
57
|
+
* `variant` is not only how the toast looks. It decides how urgently the message is
|
|
58
|
+
* announced and whether it expires, because those three answers are one answer: **an error
|
|
59
|
+
* is the message the reader has to see, hear, and keep.** So `danger` is announced
|
|
60
|
+
* assertively and never times out, and every other variant is polite and does.
|
|
61
|
+
*
|
|
62
|
+
* The alternative was a second attribute for politeness, and it was rejected for what it
|
|
63
|
+
* makes possible rather than for what it costs: two knobs can disagree, and a polite error
|
|
64
|
+
* or an assertive success is a defect nothing reports. The issue behind this component
|
|
65
|
+
* asked for `assertive` to be *reserved for errors* — a rule the API can hold is worth more
|
|
66
|
+
* than a rule the documentation states. What it gives up is stated in `docs/toast.md`:
|
|
67
|
+
* there is no way to write an assertive success.
|
|
68
|
+
*
|
|
69
|
+
* **The colour is redundant and must stay redundant.** WCAG 1.4.1 asks that colour never be
|
|
70
|
+
* the only carrier of information, and here it never is: the message says what happened and
|
|
71
|
+
* the edge agrees with it. That is also what makes the component correct under
|
|
72
|
+
* `forced-colors`, where the edge goes flat and nothing is lost.
|
|
73
|
+
*
|
|
74
|
+
* ## Dismissal
|
|
75
|
+
*
|
|
76
|
+
* Manual always, timed unless the toast is an error or `duration` is `0`. There is
|
|
77
|
+
* deliberately no way to remove the dismiss button: a toast that cannot be dismissed *and*
|
|
78
|
+
* does not expire is a permanent obstruction, and that combination is one attribute away in
|
|
79
|
+
* every kit that offers the knob.
|
|
80
|
+
*
|
|
81
|
+
* The timer stops while the pointer is over the toast or the focus is inside it, and starts
|
|
82
|
+
* again when both have left — a notice must not expire while it is being read, which is
|
|
83
|
+
* WCAG 2.2.1 aimed at the only time limit this component has.
|
|
84
|
+
*
|
|
85
|
+
* **A dismissed toast removes itself.** `ui-dismiss` is dispatched first, while the element
|
|
86
|
+
* is still in the tree so the event can reach a listener above it; a framework rendering a
|
|
87
|
+
* list of toasts drops the entry there rather than leaving the element to be put back.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```html
|
|
91
|
+
* <ui-toaster>
|
|
92
|
+
* <ui-toast variant="success">Saved.</ui-toast>
|
|
93
|
+
* </ui-toaster>
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare class UiToast extends LitElement {
|
|
97
|
+
#private;
|
|
98
|
+
static readonly styles: import("lit").CSSResult;
|
|
99
|
+
static readonly properties: {
|
|
100
|
+
variant: {
|
|
101
|
+
type: StringConstructor;
|
|
102
|
+
reflect: boolean;
|
|
103
|
+
};
|
|
104
|
+
duration: {
|
|
105
|
+
type: NumberConstructor;
|
|
106
|
+
};
|
|
107
|
+
dismissLabel: {
|
|
108
|
+
type: StringConstructor;
|
|
109
|
+
attribute: string;
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* What this toast is telling the reader.
|
|
114
|
+
*
|
|
115
|
+
* Reflected, because it is what the stylesheet selects on — and because it is the
|
|
116
|
+
* attribute a host reads back to find out how the toast will behave.
|
|
117
|
+
*
|
|
118
|
+
* A plain field rather than the `accessor` keyword, for the reason `src/button.ts`
|
|
119
|
+
* states beside its own.
|
|
120
|
+
*/
|
|
121
|
+
variant: ToastVariant;
|
|
122
|
+
/**
|
|
123
|
+
* How long the toast waits before dismissing itself, in milliseconds; `0` never.
|
|
124
|
+
*
|
|
125
|
+
* Ignored when the variant is `danger`, which never expires. Not a token, for the
|
|
126
|
+
* reason the default carries: every duration name collapses under reduced motion, and
|
|
127
|
+
* a dwell time that collapsed would take the notice away from the reader who asked for
|
|
128
|
+
* less movement.
|
|
129
|
+
*/
|
|
130
|
+
duration: number;
|
|
131
|
+
/**
|
|
132
|
+
* The accessible name of the dismiss button.
|
|
133
|
+
*
|
|
134
|
+
* This package's one user-facing string, and an attribute precisely because it is one:
|
|
135
|
+
* a page that is not in English replaces it rather than forking the component. It names
|
|
136
|
+
* the button and never appears on screen, which is why there is no way to leave it
|
|
137
|
+
* empty — an unnamed control is the failure this default exists to prevent.
|
|
138
|
+
*/
|
|
139
|
+
dismissLabel: string;
|
|
140
|
+
connectedCallback(): void;
|
|
141
|
+
disconnectedCallback(): void;
|
|
142
|
+
willUpdate(): void;
|
|
143
|
+
render(): TemplateResult;
|
|
144
|
+
/**
|
|
145
|
+
* Runs the exit, announces it, and takes the toast off the page.
|
|
146
|
+
*
|
|
147
|
+
* Bound as a field so it can be handed to a listener and called as a method without
|
|
148
|
+
* either losing `this`.
|
|
149
|
+
*/
|
|
150
|
+
readonly dismiss: () => void;
|
|
151
|
+
}
|
|
152
|
+
declare global {
|
|
153
|
+
interface HTMLElementTagNameMap {
|
|
154
|
+
'ui-toaster': UiToaster;
|
|
155
|
+
'ui-toast': UiToast;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=toast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toast.d.ts","sourceRoot":"","sources":["../src/toast.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,KAAK,cAAc,EAAE,MAAM,KAAK,CAAC;AAGjE,gGAAgG;AAChG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAqBrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,SAAU,SAAQ,UAAU;IACrC,gBAAyB,MAAM,0BAiD7B;IAEO,iBAAiB,IAAI,IAAI;IAazB,MAAM,IAAI,cAAc;CAMpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,qBAAa,OAAQ,SAAQ,UAAU;;IACnC,gBAAyB,MAAM,0BAqH7B;IAEF,gBAAyB,UAAU;;;;;;;;;;;;MAIjC;IAEF;;;;;;;;OAQG;IACH,OAAO,EAAE,YAAY,CAAU;IAE/B;;;;;;;OAOG;IACH,QAAQ,SAAS;IAEjB;;;;;;;OAOG;IACH,YAAY,SAAa;IAoChB,iBAAiB,IAAI,IAAI;IAwBzB,oBAAoB,IAAI,IAAI;IAO5B,UAAU,IAAI,IAAI;IAQlB,MAAM,IAAI,cAAc;IAsBjC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,QAAO,IAAI,CAEzB;CA0DL;AAWD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,qBAAqB;QAC3B,YAAY,EAAE,SAAS,CAAC;QACxB,UAAU,EAAE,OAAO,CAAC;KACvB;CACJ"}
|