@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.
@@ -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"}
@@ -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"}