@camp.dev/bones 0.4.0 → 0.5.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.
- package/README.md +61 -106
- package/package.json +4 -36
- package/src/css/bones.css +1008 -134
- package/dist/core/attributes.d.mts +0 -25
- package/dist/core/attributes.mjs +0 -36
- package/dist/css/auto.css +0 -1105
- package/dist/css/bones.css +0 -197
- package/dist/element/boundary.d.mts +0 -26
- package/dist/element/boundary.mjs +0 -220
- package/dist/element/index.d.mts +0 -14
- package/dist/element/index.mjs +0 -6
- package/dist/element/measure.mjs +0 -99
- package/dist/element/overlay.mjs +0 -184
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -2
- package/dist/react/boundary.d.mts +0 -40
- package/dist/react/boundary.mjs +0 -21
- package/dist/react/create-bones.d.mts +0 -23
- package/dist/react/create-bones.mjs +0 -69
- package/dist/react/index.d.mts +0 -4
- package/dist/react/index.mjs +0 -4
- package/dist/server/bootstrap.d.mts +0 -4
- package/dist/server/bootstrap.mjs +0 -3
- package/dist/server/index.d.mts +0 -17
- package/dist/server/index.mjs +0 -57
- package/src/css/auto.css +0 -1105
package/dist/css/bones.css
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
:root {
|
|
2
|
-
/* Bones derive their color from the text color in effect at the bone, so
|
|
3
|
-
they inherit the page's own contrast guarantee on any background in any
|
|
4
|
-
scheme (BON-13). currentColor resolves where var() is used, not here.
|
|
5
|
-
The alpha reset matters: bones hide their content by zeroing the alpha
|
|
6
|
-
of the color property (never with the transparent keyword, which would
|
|
7
|
-
discard the channels), and the mix restores it. */
|
|
8
|
-
--bone-base: color-mix(in srgb, rgb(from currentcolor r g b / 1) 12%, transparent);
|
|
9
|
-
--bone-highlight: color-mix(in srgb, rgb(from currentcolor r g b / 1) 6%, transparent);
|
|
10
|
-
--bone-radius: 4px;
|
|
11
|
-
--bone-duration: 1.5s;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
[data-bone="text"] {
|
|
15
|
-
color: rgb(from currentcolor r g b / 0);
|
|
16
|
-
position: relative;
|
|
17
|
-
min-width: 4ch;
|
|
18
|
-
min-height: 1lh;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
[data-bone-line] {
|
|
22
|
-
display: block;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
[data-bone-line]:last-child {
|
|
26
|
-
width: 69%;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
[data-bone="text"]::before {
|
|
30
|
-
content: "\200b";
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
[data-bone="text"]::after {
|
|
34
|
-
content: "";
|
|
35
|
-
position: absolute;
|
|
36
|
-
inset-inline: 0;
|
|
37
|
-
top: calc((1lh + 1cap) / 2 - 1ex);
|
|
38
|
-
height: 1ex;
|
|
39
|
-
background-color: var(--bone-base);
|
|
40
|
-
border-radius: var(--bone-radius);
|
|
41
|
-
pointer-events: none;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
[data-bone="text"][style*="--bone-length"] {
|
|
45
|
-
width: calc(var(--bone-length) * 1ch);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
[data-bone="text"][style*="--bone-contained"] {
|
|
49
|
-
min-width: unset;
|
|
50
|
-
display: inline-flex;
|
|
51
|
-
align-items: center;
|
|
52
|
-
box-sizing: content-box;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
[data-bone="text"][style*="--bone-contained"]::after {
|
|
56
|
-
flex: 1;
|
|
57
|
-
position: static;
|
|
58
|
-
inset-inline: unset;
|
|
59
|
-
top: unset;
|
|
60
|
-
transform: none;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
[data-bone="text"][style*="--bone-contained"][style*="--bone-length"] {
|
|
64
|
-
min-width: calc(var(--bone-length) * 1ch);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
[data-bone="block"] {
|
|
68
|
-
display: inline-block;
|
|
69
|
-
background-color: var(--bone-base);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
img[data-bone="block"],
|
|
73
|
-
video[data-bone="block"] {
|
|
74
|
-
color: rgb(from currentcolor r g b / 0);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
[data-bone="container"] {
|
|
78
|
-
position: relative;
|
|
79
|
-
overflow: hidden;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
[data-bone="container"]::before {
|
|
83
|
-
content: "";
|
|
84
|
-
position: absolute;
|
|
85
|
-
inset: 0;
|
|
86
|
-
background-color: var(--bone-base);
|
|
87
|
-
z-index: 1;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
[data-bone="container"] > * {
|
|
91
|
-
visibility: hidden;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
@keyframes bone-shimmer {
|
|
95
|
-
0% {
|
|
96
|
-
background-position: 200% 0;
|
|
97
|
-
}
|
|
98
|
-
100% {
|
|
99
|
-
background-position: -200% 0;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
@keyframes bone-pulse {
|
|
104
|
-
0%,
|
|
105
|
-
100% {
|
|
106
|
-
opacity: 1;
|
|
107
|
-
}
|
|
108
|
-
50% {
|
|
109
|
-
opacity: 0.5;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/* Marked bones shimmer by default, the same as auto bones and the measured
|
|
114
|
-
overlay (BON-16). data-bone-animate="none" is the opt-out; the @scope
|
|
115
|
-
blocks below override this at higher specificity, so their order relative
|
|
116
|
-
to this rule does not matter. */
|
|
117
|
-
[data-bone="text"]::after,
|
|
118
|
-
[data-bone="block"],
|
|
119
|
-
[data-bone="container"]::before {
|
|
120
|
-
animation: bone-shimmer var(--bone-duration) ease-in-out infinite;
|
|
121
|
-
background: linear-gradient(
|
|
122
|
-
90deg,
|
|
123
|
-
var(--bone-base) 25%,
|
|
124
|
-
var(--bone-highlight) 50%,
|
|
125
|
-
var(--bone-base) 75%
|
|
126
|
-
);
|
|
127
|
-
background-size: 200% 100%;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
@media (prefers-reduced-motion: reduce) {
|
|
131
|
-
[data-bone="text"]::after,
|
|
132
|
-
[data-bone="block"],
|
|
133
|
-
[data-bone="container"]::before {
|
|
134
|
-
animation: bone-pulse 2s ease-in-out infinite;
|
|
135
|
-
background: var(--bone-base);
|
|
136
|
-
background-size: auto;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/* :is(:scope, :scope *) lets the attribute work from the bone itself, not
|
|
141
|
-
only from a wrapper: a scoped selector's implicit :scope prefix matches
|
|
142
|
-
strict descendants only, so a plain compound never matches the scope root
|
|
143
|
-
(BON-17). The reduced-motion override sits inside each animated scope so it
|
|
144
|
-
matches at the scope's own specificity; "none" has no override because none
|
|
145
|
-
still means none. */
|
|
146
|
-
@scope ([data-bone-animate="shimmer"]) to ([data-bone-animate]:not([data-bone-animate="shimmer"])) {
|
|
147
|
-
[data-bone="text"]:is(:scope, :scope *)::after,
|
|
148
|
-
[data-bone="block"]:is(:scope, :scope *),
|
|
149
|
-
[data-bone="container"]:is(:scope, :scope *)::before {
|
|
150
|
-
animation: bone-shimmer var(--bone-duration) ease-in-out infinite;
|
|
151
|
-
background: linear-gradient(
|
|
152
|
-
90deg,
|
|
153
|
-
var(--bone-base) 25%,
|
|
154
|
-
var(--bone-highlight) 50%,
|
|
155
|
-
var(--bone-base) 75%
|
|
156
|
-
);
|
|
157
|
-
background-size: 200% 100%;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
@media (prefers-reduced-motion: reduce) {
|
|
161
|
-
[data-bone="text"]:is(:scope, :scope *)::after,
|
|
162
|
-
[data-bone="block"]:is(:scope, :scope *),
|
|
163
|
-
[data-bone="container"]:is(:scope, :scope *)::before {
|
|
164
|
-
animation: bone-pulse 2s ease-in-out infinite;
|
|
165
|
-
background: var(--bone-base);
|
|
166
|
-
background-size: auto;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
@scope ([data-bone-animate="pulse"]) to ([data-bone-animate]:not([data-bone-animate="pulse"])) {
|
|
172
|
-
[data-bone="text"]:is(:scope, :scope *)::after,
|
|
173
|
-
[data-bone="block"]:is(:scope, :scope *),
|
|
174
|
-
[data-bone="container"]:is(:scope, :scope *)::before {
|
|
175
|
-
animation: bone-pulse var(--bone-duration) ease-in-out infinite;
|
|
176
|
-
background: var(--bone-base);
|
|
177
|
-
background-size: auto;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
@media (prefers-reduced-motion: reduce) {
|
|
181
|
-
[data-bone="text"]:is(:scope, :scope *)::after,
|
|
182
|
-
[data-bone="block"]:is(:scope, :scope *),
|
|
183
|
-
[data-bone="container"]:is(:scope, :scope *)::before {
|
|
184
|
-
animation: bone-pulse 2s ease-in-out infinite;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
@scope ([data-bone-animate="none"]) to ([data-bone-animate]:not([data-bone-animate="none"])) {
|
|
190
|
-
[data-bone="text"]:is(:scope, :scope *)::after,
|
|
191
|
-
[data-bone="block"]:is(:scope, :scope *),
|
|
192
|
-
[data-bone="container"]:is(:scope, :scope *)::before {
|
|
193
|
-
animation: none;
|
|
194
|
-
background: var(--bone-base);
|
|
195
|
-
background-size: auto;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
//#region src/element/boundary.d.ts
|
|
2
|
-
declare const DEFAULT_DELAY = 200;
|
|
3
|
-
declare const DEFAULT_MIN_DURATION = 400;
|
|
4
|
-
declare const Base: typeof HTMLElement;
|
|
5
|
-
declare class BonesBoundary extends Base {
|
|
6
|
-
#private;
|
|
7
|
-
static readonly observedAttributes: string[];
|
|
8
|
-
get busy(): boolean;
|
|
9
|
-
set busy(value: boolean);
|
|
10
|
-
get force(): boolean;
|
|
11
|
-
set force(value: boolean);
|
|
12
|
-
get delay(): number;
|
|
13
|
-
set delay(value: number);
|
|
14
|
-
get minDuration(): number;
|
|
15
|
-
set minDuration(value: number);
|
|
16
|
-
get transition(): "auto" | "none";
|
|
17
|
-
set transition(value: "auto" | "none");
|
|
18
|
-
get precision(): "css" | "measured";
|
|
19
|
-
set precision(value: "css" | "measured");
|
|
20
|
-
get showing(): boolean;
|
|
21
|
-
connectedCallback(): void;
|
|
22
|
-
disconnectedCallback(): void;
|
|
23
|
-
attributeChangedCallback(name: string): void;
|
|
24
|
-
}
|
|
25
|
-
//#endregion
|
|
26
|
-
export { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION };
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import { MeasuredOverlay } from "./overlay.mjs";
|
|
2
|
-
//#region src/element/boundary.ts
|
|
3
|
-
const DEFAULT_DELAY = 200;
|
|
4
|
-
const DEFAULT_MIN_DURATION = 400;
|
|
5
|
-
const UPGRADE_PROPERTIES = [
|
|
6
|
-
"busy",
|
|
7
|
-
"force",
|
|
8
|
-
"delay",
|
|
9
|
-
"minDuration",
|
|
10
|
-
"transition",
|
|
11
|
-
"precision"
|
|
12
|
-
];
|
|
13
|
-
const swallow = () => {};
|
|
14
|
-
function parseMs(value, fallback) {
|
|
15
|
-
if (value === null || value.trim() === "") return fallback;
|
|
16
|
-
const ms = Number(value);
|
|
17
|
-
return Number.isFinite(ms) && ms >= 0 ? ms : fallback;
|
|
18
|
-
}
|
|
19
|
-
const Base = typeof HTMLElement === "undefined" ? class {} : HTMLElement;
|
|
20
|
-
var BonesBoundary = class extends Base {
|
|
21
|
-
static observedAttributes = [
|
|
22
|
-
"busy",
|
|
23
|
-
"force",
|
|
24
|
-
"aria-busy",
|
|
25
|
-
"inert",
|
|
26
|
-
"precision"
|
|
27
|
-
];
|
|
28
|
-
#state = "idle";
|
|
29
|
-
#timer;
|
|
30
|
-
#connected = false;
|
|
31
|
-
#shownAt = 0;
|
|
32
|
-
#hideToken = 0;
|
|
33
|
-
#writingOutput = false;
|
|
34
|
-
#overlay = new MeasuredOverlay(this);
|
|
35
|
-
get busy() {
|
|
36
|
-
return this.hasAttribute("busy");
|
|
37
|
-
}
|
|
38
|
-
set busy(value) {
|
|
39
|
-
this.toggleAttribute("busy", Boolean(value));
|
|
40
|
-
}
|
|
41
|
-
get force() {
|
|
42
|
-
return this.hasAttribute("force");
|
|
43
|
-
}
|
|
44
|
-
set force(value) {
|
|
45
|
-
this.toggleAttribute("force", Boolean(value));
|
|
46
|
-
}
|
|
47
|
-
get delay() {
|
|
48
|
-
return parseMs(this.getAttribute("delay"), 200);
|
|
49
|
-
}
|
|
50
|
-
set delay(value) {
|
|
51
|
-
if (value === null || value === void 0) this.removeAttribute("delay");
|
|
52
|
-
else this.setAttribute("delay", String(value));
|
|
53
|
-
}
|
|
54
|
-
get minDuration() {
|
|
55
|
-
return parseMs(this.getAttribute("min-duration"), 400);
|
|
56
|
-
}
|
|
57
|
-
set minDuration(value) {
|
|
58
|
-
if (value === null || value === void 0) this.removeAttribute("min-duration");
|
|
59
|
-
else this.setAttribute("min-duration", String(value));
|
|
60
|
-
}
|
|
61
|
-
get transition() {
|
|
62
|
-
return this.getAttribute("transition") === "none" ? "none" : "auto";
|
|
63
|
-
}
|
|
64
|
-
set transition(value) {
|
|
65
|
-
if (value === "none") this.setAttribute("transition", "none");
|
|
66
|
-
else this.removeAttribute("transition");
|
|
67
|
-
}
|
|
68
|
-
get precision() {
|
|
69
|
-
return this.getAttribute("precision") === "measured" ? "measured" : "css";
|
|
70
|
-
}
|
|
71
|
-
set precision(value) {
|
|
72
|
-
if (value === "measured") this.setAttribute("precision", "measured");
|
|
73
|
-
else this.removeAttribute("precision");
|
|
74
|
-
}
|
|
75
|
-
get showing() {
|
|
76
|
-
return this.#state === "showing" || this.#state === "draining" || this.#state === "hiding";
|
|
77
|
-
}
|
|
78
|
-
connectedCallback() {
|
|
79
|
-
for (const name of UPGRADE_PROPERTIES) this.#upgradeProperty(name);
|
|
80
|
-
this.#connected = true;
|
|
81
|
-
this.#syncPrecision();
|
|
82
|
-
if (this.getAttribute("aria-busy") === "true" && !this.showing) {
|
|
83
|
-
this.#show();
|
|
84
|
-
if (!this.busy && !this.force) this.#evaluate();
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
this.#evaluate();
|
|
88
|
-
}
|
|
89
|
-
disconnectedCallback() {
|
|
90
|
-
this.#overlay.pause();
|
|
91
|
-
this.#connected = false;
|
|
92
|
-
this.#clearTimer();
|
|
93
|
-
if (this.#state === "pending") this.#state = "idle";
|
|
94
|
-
else if (this.#state === "hiding") this.#state = "showing";
|
|
95
|
-
}
|
|
96
|
-
attributeChangedCallback(name) {
|
|
97
|
-
if (!this.#connected) return;
|
|
98
|
-
if (name === "aria-busy" || name === "inert") {
|
|
99
|
-
this.#defendOutput();
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
if (name === "precision") {
|
|
103
|
-
this.#syncPrecision();
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
this.#evaluate();
|
|
107
|
-
}
|
|
108
|
-
#defendOutput() {
|
|
109
|
-
if (this.#writingOutput) return;
|
|
110
|
-
if (this.#state !== "showing" && this.#state !== "draining") return;
|
|
111
|
-
if (this.getAttribute("aria-busy") === "true" && this.hasAttribute("inert")) return;
|
|
112
|
-
this.#writeOutput(true);
|
|
113
|
-
}
|
|
114
|
-
#syncPrecision() {
|
|
115
|
-
if (this.precision === "measured") {
|
|
116
|
-
this.#overlay.prepare();
|
|
117
|
-
if (this.showing) this.#overlay.activate();
|
|
118
|
-
} else this.#overlay.deactivate();
|
|
119
|
-
}
|
|
120
|
-
#upgradeProperty(name) {
|
|
121
|
-
if (!Object.prototype.hasOwnProperty.call(this, name)) return;
|
|
122
|
-
const self = this;
|
|
123
|
-
const value = self[name];
|
|
124
|
-
delete self[name];
|
|
125
|
-
self[name] = value;
|
|
126
|
-
}
|
|
127
|
-
#clearTimer() {
|
|
128
|
-
if (this.#timer !== void 0) clearTimeout(this.#timer);
|
|
129
|
-
this.#timer = void 0;
|
|
130
|
-
}
|
|
131
|
-
#evaluate() {
|
|
132
|
-
if (this.force) {
|
|
133
|
-
if (this.#state === "draining" || this.#state === "hiding") this.#resume();
|
|
134
|
-
else if (this.#state !== "showing") this.#show();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
if (this.busy) {
|
|
138
|
-
if (this.#state === "idle") {
|
|
139
|
-
const delay = this.delay;
|
|
140
|
-
if (delay === 0) this.#show();
|
|
141
|
-
else {
|
|
142
|
-
this.#state = "pending";
|
|
143
|
-
this.#timer = setTimeout(() => this.#show(), delay);
|
|
144
|
-
}
|
|
145
|
-
} else if (this.#state === "draining" || this.#state === "hiding") this.#resume();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (this.#state === "pending") {
|
|
149
|
-
this.#clearTimer();
|
|
150
|
-
this.#state = "idle";
|
|
151
|
-
} else if (this.#state === "showing" || this.#state === "draining") {
|
|
152
|
-
this.#clearTimer();
|
|
153
|
-
const remaining = this.#shownAt + this.minDuration - Date.now();
|
|
154
|
-
if (remaining <= 0) this.#hide();
|
|
155
|
-
else {
|
|
156
|
-
this.#state = "draining";
|
|
157
|
-
this.#timer = setTimeout(() => this.#hide(), remaining);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
#resume() {
|
|
162
|
-
this.#clearTimer();
|
|
163
|
-
this.#state = "showing";
|
|
164
|
-
this.#writeOutput(true);
|
|
165
|
-
}
|
|
166
|
-
#show() {
|
|
167
|
-
this.#clearTimer();
|
|
168
|
-
this.#state = "showing";
|
|
169
|
-
this.#shownAt = Date.now();
|
|
170
|
-
this.#writeOutput(true);
|
|
171
|
-
if (this.precision === "measured") this.#overlay.activate();
|
|
172
|
-
this.dispatchEvent(new CustomEvent("bones:show", {
|
|
173
|
-
bubbles: true,
|
|
174
|
-
composed: true
|
|
175
|
-
}));
|
|
176
|
-
}
|
|
177
|
-
#hide() {
|
|
178
|
-
this.#clearTimer();
|
|
179
|
-
this.#state = "hiding";
|
|
180
|
-
const token = ++this.#hideToken;
|
|
181
|
-
const update = () => {
|
|
182
|
-
if (this.#state !== "hiding" || token !== this.#hideToken) return;
|
|
183
|
-
this.#state = "idle";
|
|
184
|
-
this.#writeOutput(false);
|
|
185
|
-
this.#overlay.deactivate();
|
|
186
|
-
this.dispatchEvent(new CustomEvent("bones:hide", {
|
|
187
|
-
bubbles: true,
|
|
188
|
-
composed: true
|
|
189
|
-
}));
|
|
190
|
-
};
|
|
191
|
-
if (this.#canTransition()) {
|
|
192
|
-
const transition = document.startViewTransition(update);
|
|
193
|
-
transition?.ready?.catch(swallow);
|
|
194
|
-
transition?.updateCallbackDone?.catch(swallow);
|
|
195
|
-
transition?.finished?.catch(swallow);
|
|
196
|
-
} else update();
|
|
197
|
-
}
|
|
198
|
-
#writeOutput(shown) {
|
|
199
|
-
this.#writingOutput = true;
|
|
200
|
-
try {
|
|
201
|
-
if (shown) {
|
|
202
|
-
this.setAttribute("aria-busy", "true");
|
|
203
|
-
this.toggleAttribute("inert", true);
|
|
204
|
-
} else {
|
|
205
|
-
this.removeAttribute("aria-busy");
|
|
206
|
-
this.removeAttribute("inert");
|
|
207
|
-
}
|
|
208
|
-
} finally {
|
|
209
|
-
this.#writingOutput = false;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
#canTransition() {
|
|
213
|
-
if (this.transition === "none") return false;
|
|
214
|
-
if (typeof document.startViewTransition !== "function") return false;
|
|
215
|
-
if (typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) return false;
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
};
|
|
219
|
-
//#endregion
|
|
220
|
-
export { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION };
|
package/dist/element/index.d.mts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION } from "./boundary.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/element/index.d.ts
|
|
4
|
-
declare global {
|
|
5
|
-
interface HTMLElementTagNameMap {
|
|
6
|
-
"bones-boundary": BonesBoundary;
|
|
7
|
-
}
|
|
8
|
-
interface HTMLElementEventMap {
|
|
9
|
-
"bones:show": CustomEvent;
|
|
10
|
-
"bones:hide": CustomEvent;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
//#endregion
|
|
14
|
-
export { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION };
|
package/dist/element/index.mjs
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION } from "./boundary.mjs";
|
|
2
|
-
//#region src/element/index.ts
|
|
3
|
-
if (typeof customElements !== "undefined") if (customElements.get("bones-boundary")) console.warn("bones-boundary is already defined; @camp.dev/bones/element did not register");
|
|
4
|
-
else customElements.define("bones-boundary", BonesBoundary);
|
|
5
|
-
//#endregion
|
|
6
|
-
export { BonesBoundary, DEFAULT_DELAY, DEFAULT_MIN_DURATION };
|
package/dist/element/measure.mjs
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
//#region src/element/measure.ts
|
|
2
|
-
const BLOCK_TAGS = new Set([
|
|
3
|
-
"img",
|
|
4
|
-
"svg",
|
|
5
|
-
"video",
|
|
6
|
-
"canvas",
|
|
7
|
-
"picture",
|
|
8
|
-
"iframe",
|
|
9
|
-
"embed",
|
|
10
|
-
"object",
|
|
11
|
-
"audio",
|
|
12
|
-
"button",
|
|
13
|
-
"input",
|
|
14
|
-
"select",
|
|
15
|
-
"textarea",
|
|
16
|
-
"progress",
|
|
17
|
-
"meter"
|
|
18
|
-
]);
|
|
19
|
-
const TEXT_BAR_SCALE = .55;
|
|
20
|
-
function verticalOverlap(a, b) {
|
|
21
|
-
return Math.min(a.top + a.height, b.top + b.height) - Math.max(a.top, b.top);
|
|
22
|
-
}
|
|
23
|
-
function mergeLineRects(rects) {
|
|
24
|
-
const sorted = [...rects].sort((a, b) => a.top - b.top || a.left - b.left);
|
|
25
|
-
const merged = [];
|
|
26
|
-
for (const rect of sorted) {
|
|
27
|
-
const line = merged.findLast((candidate) => {
|
|
28
|
-
if (verticalOverlap(candidate, rect) < Math.min(candidate.height, rect.height) / 2) return false;
|
|
29
|
-
return rect.left - (candidate.left + candidate.width) <= Math.max(candidate.height, rect.height) / 2;
|
|
30
|
-
});
|
|
31
|
-
if (line === void 0) {
|
|
32
|
-
merged.push({ ...rect });
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
const right = Math.max(line.left + line.width, rect.left + rect.width);
|
|
36
|
-
const bottom = Math.max(line.top + line.height, rect.top + rect.height);
|
|
37
|
-
line.left = Math.min(line.left, rect.left);
|
|
38
|
-
line.top = Math.min(line.top, rect.top);
|
|
39
|
-
line.width = right - line.left;
|
|
40
|
-
line.height = bottom - line.top;
|
|
41
|
-
}
|
|
42
|
-
return merged;
|
|
43
|
-
}
|
|
44
|
-
function isVisible(rect) {
|
|
45
|
-
return rect.width > 0 && rect.height > 0;
|
|
46
|
-
}
|
|
47
|
-
function toRect(rect) {
|
|
48
|
-
return {
|
|
49
|
-
left: rect.left,
|
|
50
|
-
top: rect.top,
|
|
51
|
-
width: rect.width,
|
|
52
|
-
height: rect.height
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
function measureBones(root) {
|
|
56
|
-
const doc = root.ownerDocument;
|
|
57
|
-
const blocks = [];
|
|
58
|
-
const textRects = [];
|
|
59
|
-
const visit = (node) => {
|
|
60
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
61
|
-
if (node.data.trim() === "") return;
|
|
62
|
-
const range = doc.createRange();
|
|
63
|
-
range.selectNodeContents(node);
|
|
64
|
-
if (typeof range.getClientRects !== "function") return;
|
|
65
|
-
for (const rect of Array.from(range.getClientRects())) {
|
|
66
|
-
const converted = toRect(rect);
|
|
67
|
-
if (isVisible(converted)) textRects.push(converted);
|
|
68
|
-
}
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
72
|
-
const el = node;
|
|
73
|
-
if (el.getAttribute("data-bones-auto") === "off") return;
|
|
74
|
-
if (BLOCK_TAGS.has(el.localName)) {
|
|
75
|
-
const rect = toRect(el.getBoundingClientRect());
|
|
76
|
-
if (isVisible(rect)) blocks.push({
|
|
77
|
-
kind: "block",
|
|
78
|
-
...rect
|
|
79
|
-
});
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
for (const child of node.childNodes) visit(child);
|
|
83
|
-
};
|
|
84
|
-
for (const child of root.childNodes) visit(child);
|
|
85
|
-
const bones = [...blocks];
|
|
86
|
-
for (const line of mergeLineRects(textRects)) {
|
|
87
|
-
const height = line.height * TEXT_BAR_SCALE;
|
|
88
|
-
bones.push({
|
|
89
|
-
kind: "text",
|
|
90
|
-
left: line.left,
|
|
91
|
-
top: line.top + (line.height - height) / 2,
|
|
92
|
-
width: line.width,
|
|
93
|
-
height
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
return bones;
|
|
97
|
-
}
|
|
98
|
-
//#endregion
|
|
99
|
-
export { measureBones };
|