@neovici/cosmoz-utils 6.26.0 → 6.27.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.
@@ -0,0 +1,27 @@
1
+ import { type ElementPart } from 'lit-html';
2
+ import { AsyncDirective } from 'lit-html/async-directive.js';
3
+ /**
4
+ * The directive expects this css. Adopt it on your component, set the
5
+ * class `cz-overflow-band` on the band slot, and give it a `max-height`
6
+ * to match one row.
7
+ */
8
+ export declare const overflowStyle: CSSStyleSheet;
9
+ /**
10
+ * The directive marks the elements that overflow with "[overflowing]"
11
+ * and reports the full list via `onOverflow`. The effect relies mainly
12
+ * on css flex wrapping, so make sure to use the accompanying stylesheet
13
+ * (or match in your own css).
14
+ */
15
+ export interface OverflowConfig {
16
+ onOverflow: (overflowing: Set<HTMLElement>) => void;
17
+ }
18
+ declare class OverflowDirective extends AsyncDirective {
19
+ #private;
20
+ _slot?: HTMLSlotElement;
21
+ _onOverflow?: (overflowing: Set<HTMLElement>) => void;
22
+ render(config: OverflowConfig): symbol;
23
+ update(part: ElementPart, [config]: [OverflowConfig]): symbol;
24
+ disconnected(): void;
25
+ }
26
+ export declare const overflow: (config: OverflowConfig) => import("lit-html/directive.js").DirectiveResult<typeof OverflowDirective>;
27
+ export {};
@@ -0,0 +1,121 @@
1
+ import { css } from '@pionjs/pion';
2
+ import { noChange } from 'lit-html';
3
+ import { AsyncDirective, directive } from 'lit-html/async-directive.js';
4
+ import { sheet } from '../sheet.js';
5
+ /**
6
+ * The directive expects this css. Adopt it on your component, set the
7
+ * class `cz-overflow-band` on the band slot, and give it a `max-height`
8
+ * to match one row.
9
+ */
10
+ export const overflowStyle = sheet(css `
11
+ slot.cz-overflow-band {
12
+ display: flex;
13
+ flex-wrap: wrap;
14
+ align-items: flex-start;
15
+ overflow: clip;
16
+ }
17
+
18
+ ::slotted([overflowing]) {
19
+ visibility: hidden;
20
+ }
21
+ `);
22
+ const members = (slot) => slot.assignedElements({ flatten: true });
23
+ const stable = (a, b) => a != null &&
24
+ b != null &&
25
+ a.size === b.size &&
26
+ [...b].every((el) => a.has(el));
27
+ class OverflowDirective extends AsyncDirective {
28
+ _slot;
29
+ _onOverflow;
30
+ #clipped = new Map();
31
+ #last;
32
+ #observer;
33
+ #classify = (entries) => {
34
+ entries.forEach((entry) => {
35
+ const member = entry.target;
36
+ this.#clipped.set(member, entry.boundingClientRect.height > 0 &&
37
+ entry.intersectionRect.height === 0);
38
+ });
39
+ this.#flush();
40
+ };
41
+ #observe = (member) => {
42
+ this.#observer?.unobserve(member);
43
+ this.#observer?.observe(member);
44
+ };
45
+ #flush = () => {
46
+ if (!this._slot) {
47
+ return;
48
+ }
49
+ const current = members(this._slot);
50
+ current.forEach((member) => {
51
+ const on = this.#clipped.get(member) === true;
52
+ if (on === member.hasAttribute('overflowing')) {
53
+ return;
54
+ }
55
+ if (on) {
56
+ member.setAttribute('overflowing', '');
57
+ }
58
+ else {
59
+ member.removeAttribute('overflowing');
60
+ }
61
+ });
62
+ // a member that left the slot: forget it, stop watching it,
63
+ // remove the mark
64
+ this.#clipped.forEach((_, member) => {
65
+ if (current.includes(member)) {
66
+ return;
67
+ }
68
+ this.#clipped.delete(member);
69
+ this.#observer?.unobserve(member);
70
+ if (member.hasAttribute('overflowing')) {
71
+ member.removeAttribute('overflowing');
72
+ }
73
+ });
74
+ const next = new Set(current.filter((member) => this.#clipped.get(member) === true));
75
+ if (stable(this.#last, next)) {
76
+ return;
77
+ }
78
+ this.#last = next;
79
+ this._onOverflow?.(next);
80
+ };
81
+ #onSlotChange = () => this.#arm();
82
+ #arm = () => {
83
+ if (!this.#observer || !this._slot) {
84
+ return;
85
+ }
86
+ for (const member of members(this._slot)) {
87
+ this.#observe(member);
88
+ }
89
+ this.#flush();
90
+ };
91
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
92
+ render(config) {
93
+ return noChange;
94
+ }
95
+ update(part, [config]) {
96
+ this._onOverflow = config.onOverflow;
97
+ const slot = part.element;
98
+ if (this._slot !== slot) {
99
+ this._slot?.removeEventListener('slotchange', this.#onSlotChange);
100
+ this.#observer?.disconnect();
101
+ this.#observer = undefined;
102
+ this._slot = slot;
103
+ slot.addEventListener('slotchange', this.#onSlotChange);
104
+ }
105
+ this.#observer ??= new IntersectionObserver(this.#classify, {
106
+ root: this._slot,
107
+ threshold: [0, 1],
108
+ });
109
+ this.#arm();
110
+ return noChange;
111
+ }
112
+ disconnected() {
113
+ this._slot?.removeEventListener('slotchange', this.#onSlotChange);
114
+ this._slot = undefined;
115
+ this.#observer?.disconnect();
116
+ this.#observer = undefined;
117
+ this.#clipped.clear();
118
+ this.#last = undefined;
119
+ }
120
+ }
121
+ export const overflow = directive(OverflowDirective);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neovici/cosmoz-utils",
3
- "version": "6.26.0",
3
+ "version": "6.27.0",
4
4
  "description": "Date, money and template management functions commonly needed in Cosmoz views.",
5
5
  "keywords": [
6
6
  "polymer",