@sableui/react 0.14.0 → 0.16.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/CHANGELOG.md +131 -0
- package/DESIGN.md +3 -1
- package/bin/sable-lint.mjs +5 -1
- package/dist/{_contract-CkqXDVww.d.ts → _contract-CDa9-NdB.d.ts} +47 -1
- package/dist/blocks/index.d.ts +12 -1
- package/dist/blocks/index.js +4 -0
- package/dist/blocks/message-reactions-block.js +87 -0
- package/dist/blocks/message-reactions-block.meta.js +23 -0
- package/dist/blocks/wallet-block.js +2 -2
- package/dist/components/app-shell/app-shell-frame.js +16 -0
- package/dist/components/app-shell/app-shell-main.js +12 -0
- package/dist/components/app-shell/app-shell.js +28 -4
- package/dist/components/app-shell/app-shell.meta.js +88 -4
- package/dist/components/area-chart/area-chart.meta.js +6 -1
- package/dist/components/attachment/attachment.meta.js +2 -1
- package/dist/components/attachment/attachment.variants.js +1 -1
- package/dist/components/badge/badge.meta.js +8 -1
- package/dist/components/badge/badge.variants.js +7 -7
- package/dist/components/banner/banner.meta.js +6 -1
- package/dist/components/banner/banner.variants.js +5 -5
- package/dist/components/bar-chart/bar-chart.meta.js +6 -1
- package/dist/components/bubble/bubble.js +105 -5
- package/dist/components/bubble/bubble.meta.js +42 -6
- package/dist/components/bubble/bubble.variants.js +1 -1
- package/dist/components/bubble/index.js +2 -0
- package/dist/components/caret-menu/caret-menu.js +5 -6
- package/dist/components/chat-composer/chat-composer.meta.js +2 -2
- package/dist/components/chat-composer/chat-composer.variants.js +1 -1
- package/dist/components/color-field/color-field.js +6 -8
- package/dist/components/combobox/combobox.js +27 -5
- package/dist/components/combobox/combobox.meta.js +10 -2
- package/dist/components/command-menu/command-menu.js +14 -3
- package/dist/components/command-menu/command-menu.meta.js +9 -1
- package/dist/components/date-picker/date-picker.meta.js +2 -2
- package/dist/components/feedback/feedback.js +9 -2
- package/dist/components/feedback/feedback.meta.js +8 -1
- package/dist/components/gradient-art/gradient-art.js +8 -5
- package/dist/components/gradient-art/gradient-art.meta.js +35 -2
- package/dist/components/input/input.meta.js +11 -3
- package/dist/components/input-group/input-group.js +1 -1
- package/dist/components/input-group/input-group.meta.js +1 -1
- package/dist/components/like-button/index.js +7 -0
- package/dist/components/like-button/like-button.js +89 -0
- package/dist/components/like-button/like-button.meta.js +132 -0
- package/dist/components/line-chart/line-chart.meta.js +6 -1
- package/dist/components/menu/menu.js +1 -1
- package/dist/components/meter/meter.js +53 -7
- package/dist/components/meter/meter.meta.js +51 -4
- package/dist/components/meter/meter.variants.js +43 -7
- package/dist/components/note/note.meta.js +5 -1
- package/dist/components/note/note.variants.js +4 -4
- package/dist/components/number-field/number-field.meta.js +2 -2
- package/dist/components/otp-field/otp-field.meta.js +2 -2
- package/dist/components/panel-group/panel-group.js +5 -8
- package/dist/components/pie-chart/pie-chart.meta.js +6 -1
- package/dist/components/radar-chart/radar-chart.meta.js +6 -1
- package/dist/components/radial-chart/radial-chart.meta.js +6 -1
- package/dist/components/reaction-picker/index.js +13 -0
- package/dist/components/reaction-picker/reaction-picker.js +104 -0
- package/dist/components/reaction-picker/reaction-picker.meta.js +156 -0
- package/dist/components/search-input/search-input.meta.js +11 -3
- package/dist/components/segmented-bar/segmented-bar.meta.js +8 -1
- package/dist/components/segmented-bar/segmented-bar.variants.js +7 -7
- package/dist/components/select/select.js +1 -1
- package/dist/components/select/select.meta.js +2 -2
- package/dist/components/sheet/sheet.js +5 -4
- package/dist/components/sidebar/sidebar.js +16 -1
- package/dist/components/sidebar/sidebar.meta.js +7 -2
- package/dist/components/sparkline/sparkline.meta.js +8 -1
- package/dist/components/status-dot/status-dot.meta.js +8 -1
- package/dist/components/status-dot/status-dot.variants.js +7 -7
- package/dist/components/stepper/stepper.meta.js +2 -1
- package/dist/components/stepper/stepper.variants.js +1 -1
- package/dist/components/table/table.meta.js +4 -4
- package/dist/components/textarea/textarea.js +5 -0
- package/dist/components/textarea/textarea.meta.js +3 -3
- package/dist/components/toast/toast.js +25 -13
- package/dist/components/toast/toast.meta.js +7 -1
- package/dist/file-hashes.json +112 -100
- package/dist/foundations/accessibility.js +5 -0
- package/dist/foundations/motion.js +21 -1
- package/dist/icon-sets/reicon.js +11 -1
- package/dist/index.d.ts +425 -84
- package/dist/index.js +11 -1
- package/dist/lib/chart/types.js +8 -8
- package/dist/lib/chart/use-arrival.js +5 -4
- package/dist/lib/field-shell.js +1 -1
- package/dist/lib/highlight-glide.js +6 -6
- package/dist/lib/scrub-gesture.js +6 -6
- package/dist/lib/taxonomy.js +2 -0
- package/dist/lib/use-caret-trigger.js +11 -18
- package/dist/lib/use-match-highlight.js +69 -0
- package/dist/lib/use-smooth-wheel.js +10 -8
- package/dist/motion/Burst.js +79 -0
- package/dist/motion/index.js +2 -0
- package/dist/presets/index.d.ts +13 -2
- package/dist/presets/index.js +17 -1
- package/dist/styles.css +241 -0
- package/dist/{theme-provider-CdSicAad.d.ts → theme-provider-BydfM5Z0.d.ts} +1 -1
- package/dist/themes/_contract.js +14 -0
- package/dist/themes/atelier/atelier.css +18 -0
- package/dist/themes/atelier/index.d.ts +1 -1
- package/dist/themes/contrast.js +48 -1
- package/dist/themes/ember/ember.css +18 -0
- package/dist/themes/ember/index.d.ts +1 -1
- package/dist/themes/index.d.ts +2 -2
- package/dist/themes/meridian/index.d.ts +1 -1
- package/dist/themes/meridian/meridian.css +18 -0
- package/dist/themes/poppy/index.d.ts +1 -1
- package/dist/themes/poppy/poppy.css +18 -0
- package/dist/themes/prism/index.d.ts +1 -1
- package/dist/themes/prism/prism.css +18 -0
- package/dist/themes/sable/index.d.ts +1 -1
- package/dist/themes/sable/sable.css +18 -0
- package/dist/themes/verdant/index.d.ts +1 -1
- package/dist/themes/verdant/verdant.css +18 -0
- package/llms/blocks/message-reactions-block.md +116 -0
- package/llms/blocks/wallet-block.md +5 -4
- package/llms/components/app-shell.md +72 -3
- package/llms/components/area-chart.md +1 -1
- package/llms/components/attachment.md +1 -1
- package/llms/components/badge.md +1 -1
- package/llms/components/banner.md +1 -1
- package/llms/components/bar-chart.md +1 -1
- package/llms/components/bubble.md +17 -7
- package/llms/components/chat-composer.md +1 -1
- package/llms/components/combobox.md +2 -1
- package/llms/components/command-menu.md +3 -2
- package/llms/components/date-picker.md +1 -1
- package/llms/components/feedback.md +2 -1
- package/llms/components/gradient-art.md +28 -1
- package/llms/components/input-group.md +1 -1
- package/llms/components/input.md +4 -2
- package/llms/components/like-button.md +91 -0
- package/llms/components/line-chart.md +1 -1
- package/llms/components/meter.md +33 -4
- package/llms/components/note.md +1 -1
- package/llms/components/number-field.md +1 -1
- package/llms/components/otp-field.md +1 -1
- package/llms/components/pie-chart.md +1 -1
- package/llms/components/radar-chart.md +1 -1
- package/llms/components/radial-chart.md +1 -1
- package/llms/components/reaction-picker.md +115 -0
- package/llms/components/search-input.md +20 -2
- package/llms/components/segmented-bar.md +1 -1
- package/llms/components/select.md +1 -1
- package/llms/components/sidebar.md +3 -2
- package/llms/components/sparkline.md +1 -1
- package/llms/components/status-dot.md +1 -1
- package/llms/components/stepper.md +1 -1
- package/llms/components/table.md +2 -2
- package/llms/components/textarea.md +2 -2
- package/llms/components/toast.md +2 -1
- package/llms/foundations/accessibility.md +1 -0
- package/llms/foundations/motion.md +18 -2
- package/llms/reference/token-intent.md +22 -2
- package/llms/reference/utilities.md +9 -3
- package/llms-full.txt +596 -61
- package/llms.txt +10 -7
- package/package.json +1 -1
- package/registry.json +968 -68
- package/scripts/lint-rules.mjs +6 -3
- package/targets/ios.json +18 -0
package/dist/index.js
CHANGED
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
DENSITY_TOKENS,
|
|
19
19
|
RHYTHM_TOKENS,
|
|
20
20
|
WORKSPACE_SURFACE_TOKENS,
|
|
21
|
+
FIELD_TOKENS,
|
|
22
|
+
APP_SHELL_TOKENS,
|
|
23
|
+
MARK_TOKENS,
|
|
21
24
|
ART_TOKENS,
|
|
22
25
|
PALETTE_TOKENS,
|
|
23
26
|
TYPE_UI_TOKENS
|
|
@@ -44,6 +47,7 @@ export * from "./motion/index.js";
|
|
|
44
47
|
export * from "./components/button/index.js";
|
|
45
48
|
export * from "./components/button-group/index.js";
|
|
46
49
|
export * from "./components/confirm-button/index.js";
|
|
50
|
+
export * from "./components/like-button/index.js";
|
|
47
51
|
export * from "./components/card/index.js";
|
|
48
52
|
export * from "./components/caret-menu/index.js";
|
|
49
53
|
export * from "./components/badge/index.js";
|
|
@@ -163,11 +167,13 @@ export * from "./components/chat-composer/index.js";
|
|
|
163
167
|
export * from "./components/settings-menu/index.js";
|
|
164
168
|
export * from "./components/message/index.js";
|
|
165
169
|
export * from "./components/bubble/index.js";
|
|
170
|
+
export * from "./components/reaction-picker/index.js";
|
|
166
171
|
export * from "./components/attachment/index.js";
|
|
167
172
|
export * from "./components/marker/index.js";
|
|
168
173
|
import { Density, DensityProvider, useDensity, useAnchoredDensity, useTypeTier } from "./lib/density.js";
|
|
169
174
|
import { PresentationProvider, usePresentation } from "./lib/presentation.js";
|
|
170
175
|
import { useScrollActivity } from "./lib/use-scroll-activity.js";
|
|
176
|
+
import { useMatchHighlight } from "./lib/use-match-highlight.js";
|
|
171
177
|
import { useCopy } from "./lib/use-copy.js";
|
|
172
178
|
import { useSmoothWheel } from "./lib/use-smooth-wheel.js";
|
|
173
179
|
import {
|
|
@@ -175,8 +181,9 @@ import {
|
|
|
175
181
|
} from "./lib/use-caret-trigger.js";
|
|
176
182
|
import { STATUS_TONES, STATUS_TONE_ICON } from "./lib/status-tone.js";
|
|
177
183
|
import { PALETTE_COLORS, PALETTE_FAMILIES, PALETTE_SCALES, PALETTE_STEPS, PALETTE_TONES, isPaletteColor } from "./lib/palette.js";
|
|
178
|
-
var SABLE_UI_VERSION = "0.
|
|
184
|
+
var SABLE_UI_VERSION = "0.16.0";
|
|
179
185
|
export {
|
|
186
|
+
APP_SHELL_TOKENS,
|
|
180
187
|
ART_TOKENS,
|
|
181
188
|
CHART_SERIES_COUNT,
|
|
182
189
|
COMPONENT_GROUPS,
|
|
@@ -185,6 +192,8 @@ export {
|
|
|
185
192
|
DENSITY_TOKENS,
|
|
186
193
|
Density,
|
|
187
194
|
DensityProvider,
|
|
195
|
+
FIELD_TOKENS,
|
|
196
|
+
MARK_TOKENS,
|
|
188
197
|
MOTION_TOKENS,
|
|
189
198
|
PALETTE_COLORS,
|
|
190
199
|
PALETTE_FAMILIES,
|
|
@@ -229,6 +238,7 @@ export {
|
|
|
229
238
|
useCaretTrigger,
|
|
230
239
|
useCopy,
|
|
231
240
|
useDensity,
|
|
241
|
+
useMatchHighlight,
|
|
232
242
|
usePresentation,
|
|
233
243
|
useSableTheme,
|
|
234
244
|
useScrollActivity,
|
package/dist/lib/chart/types.js
CHANGED
|
@@ -4,18 +4,18 @@ function chartColor(index) {
|
|
|
4
4
|
return `var(--chart-${index % CHART_SERIES_COUNT + 1})`;
|
|
5
5
|
}
|
|
6
6
|
var TONE_VAR = {
|
|
7
|
-
"1": "var(--tone-1)",
|
|
8
|
-
"2": "var(--tone-2)",
|
|
9
|
-
"3": "var(--tone-3)",
|
|
10
|
-
info: "var(--tone-info)",
|
|
11
|
-
warning: "var(--tone-warning)",
|
|
7
|
+
"1": "var(--tone-1-mark)",
|
|
8
|
+
"2": "var(--tone-2-mark)",
|
|
9
|
+
"3": "var(--tone-3-mark)",
|
|
10
|
+
info: "var(--tone-info-mark)",
|
|
11
|
+
warning: "var(--tone-warning-mark)",
|
|
12
12
|
primary: "var(--primary)",
|
|
13
13
|
neutral: "var(--muted-foreground)",
|
|
14
|
-
success: "var(--success)",
|
|
15
|
-
destructive: "var(--destructive)"
|
|
14
|
+
success: "var(--success-mark)",
|
|
15
|
+
destructive: "var(--destructive-mark)"
|
|
16
16
|
};
|
|
17
17
|
function toneColor(tone) {
|
|
18
|
-
return `oklch(from ${TONE_VAR[tone]} clamp(0.5,
|
|
18
|
+
return `oklch(from ${TONE_VAR[tone]} clamp(0.5, l, 0.78) max(c, 0.1) h)`;
|
|
19
19
|
}
|
|
20
20
|
function resolveSeries(series) {
|
|
21
21
|
return series.map((s, i) => ({
|
|
@@ -25,13 +25,14 @@ function useArrival() {
|
|
|
25
25
|
cancelAnimationFrame(frame);
|
|
26
26
|
frame = requestAnimationFrame(() => onScreen() && setArrived(true));
|
|
27
27
|
};
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const listeners = new AbortController();
|
|
29
|
+
const { signal } = listeners;
|
|
30
|
+
window.addEventListener("scroll", check, { passive: true, capture: true, signal });
|
|
31
|
+
window.addEventListener("resize", check, { passive: true, signal });
|
|
30
32
|
return () => {
|
|
31
33
|
observer.disconnect();
|
|
32
34
|
cancelAnimationFrame(frame);
|
|
33
|
-
|
|
34
|
-
window.removeEventListener("resize", check);
|
|
35
|
+
listeners.abort();
|
|
35
36
|
};
|
|
36
37
|
}, [el, arrived]);
|
|
37
38
|
return [ref, arrived];
|
package/dist/lib/field-shell.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/field-shell.ts
|
|
2
|
-
var FIELD_SHELL = "rounded-sm border border-
|
|
2
|
+
var FIELD_SHELL = "rounded-sm border border-field-border bg-field motion-interactive placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
3
3
|
var MOBILE_FIELD_TIER = "max-sm:text-body-lg";
|
|
4
4
|
var FIELD_INVALID = "aria-[invalid=true]:border-destructive aria-[invalid=true]:ring-destructive/30";
|
|
5
5
|
var FIELD_SHELL_XS = "rounded-[var(--panel-field-radius,var(--radius-xs))] border-transparent bg-panel-field hover:bg-panel-field-hover";
|
|
@@ -95,16 +95,16 @@ function HighlightGlide({
|
|
|
95
95
|
mutations.observe(host, { attributes: true, attributeFilter: [follow], subtree: true, childList: true });
|
|
96
96
|
const resize = new ResizeObserver(place);
|
|
97
97
|
resize.observe(host);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
host.addEventListener("
|
|
98
|
+
const listeners = new AbortController();
|
|
99
|
+
const { signal } = listeners;
|
|
100
|
+
host.addEventListener("scroll", place, { capture: true, signal });
|
|
101
|
+
host.addEventListener("transitionend", place, { signal });
|
|
102
|
+
host.addEventListener("animationend", place, { signal });
|
|
101
103
|
return () => {
|
|
102
104
|
cancelAnimationFrame(frame);
|
|
103
105
|
mutations.disconnect();
|
|
104
106
|
resize.disconnect();
|
|
105
|
-
|
|
106
|
-
host.removeEventListener("transitionend", place);
|
|
107
|
-
host.removeEventListener("animationend", place);
|
|
107
|
+
listeners.abort();
|
|
108
108
|
host.removeAttribute("data-glide");
|
|
109
109
|
};
|
|
110
110
|
}, [follow, timing]);
|
|
@@ -15,6 +15,8 @@ function beginScrub(e, {
|
|
|
15
15
|
const startValue = value;
|
|
16
16
|
const target = e.currentTarget;
|
|
17
17
|
let moved = false;
|
|
18
|
+
const gesture = new AbortController();
|
|
19
|
+
const { signal } = gesture;
|
|
18
20
|
function onMove(ev) {
|
|
19
21
|
const dx = ev.clientX - startX;
|
|
20
22
|
if (!moved) {
|
|
@@ -37,13 +39,11 @@ function beginScrub(e, {
|
|
|
37
39
|
{ capture: true, once: true }
|
|
38
40
|
);
|
|
39
41
|
}
|
|
40
|
-
|
|
41
|
-
window.removeEventListener("pointerup", onUp);
|
|
42
|
-
window.removeEventListener("pointercancel", onUp);
|
|
42
|
+
gesture.abort();
|
|
43
43
|
}
|
|
44
|
-
window.addEventListener("pointermove", onMove);
|
|
45
|
-
window.addEventListener("pointerup", onUp);
|
|
46
|
-
window.addEventListener("pointercancel", onUp);
|
|
44
|
+
window.addEventListener("pointermove", onMove, { signal });
|
|
45
|
+
window.addEventListener("pointerup", onUp, { signal });
|
|
46
|
+
window.addEventListener("pointercancel", onUp, { signal });
|
|
47
47
|
}
|
|
48
48
|
export {
|
|
49
49
|
beginScrub
|
package/dist/lib/taxonomy.js
CHANGED
|
@@ -26,8 +26,10 @@ var COMPONENT_TAXONOMY = {
|
|
|
26
26
|
Button: ["Actions", "either"],
|
|
27
27
|
ButtonGroup: ["Actions", "either"],
|
|
28
28
|
ConfirmButton: ["Actions", "either"],
|
|
29
|
+
LikeButton: ["Actions", "either"],
|
|
29
30
|
Menubar: ["Actions", "either"],
|
|
30
31
|
OverflowMenu: ["Actions", "either"],
|
|
32
|
+
ReactionPicker: ["Actions", "either"],
|
|
31
33
|
Toolbar: ["Actions", "either"],
|
|
32
34
|
/* ── Forms ────────────────────────────────────────────────────────────────
|
|
33
35
|
Typing or entering a value, and the structure a form is built from.
|
|
@@ -36,24 +36,17 @@ function useCaretTrigger({ triggers }) {
|
|
|
36
36
|
const onInput = (event) => {
|
|
37
37
|
if (event.target === field) evaluate();
|
|
38
38
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
field.addEventListener("
|
|
43
|
-
field.addEventListener("
|
|
44
|
-
field.addEventListener("
|
|
45
|
-
field.addEventListener("
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
field.removeEventListener("click", evaluate);
|
|
51
|
-
field.removeEventListener("keyup", evaluate);
|
|
52
|
-
field.removeEventListener("compositionstart", onCompositionStart);
|
|
53
|
-
field.removeEventListener("compositionend", onCompositionEnd);
|
|
54
|
-
field.removeEventListener("blur", onBlur);
|
|
55
|
-
doc.removeEventListener("selectionchange", onSelection);
|
|
56
|
-
};
|
|
39
|
+
const listeners = new AbortController();
|
|
40
|
+
const { signal } = listeners;
|
|
41
|
+
doc.addEventListener("input", onInput, { signal });
|
|
42
|
+
field.addEventListener("focus", evaluate, { signal });
|
|
43
|
+
field.addEventListener("click", evaluate, { signal });
|
|
44
|
+
field.addEventListener("keyup", evaluate, { signal });
|
|
45
|
+
field.addEventListener("compositionstart", onCompositionStart, { signal });
|
|
46
|
+
field.addEventListener("compositionend", onCompositionEnd, { signal });
|
|
47
|
+
field.addEventListener("blur", onBlur, { signal });
|
|
48
|
+
doc.addEventListener("selectionchange", onSelection, { signal });
|
|
49
|
+
return () => listeners.abort();
|
|
57
50
|
}, [field, evaluate]);
|
|
58
51
|
const dismiss = useCallback(() => {
|
|
59
52
|
setMatch((current) => {
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/lib/use-match-highlight.ts
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
function useMatchHighlight(query, options = {}) {
|
|
6
|
+
const { selector, enabled = true } = options;
|
|
7
|
+
const [element, setElement] = useState(null);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
const highlight = enabled && element ? sharedHighlight() : null;
|
|
10
|
+
if (!highlight || !element) return;
|
|
11
|
+
let ranges = [];
|
|
12
|
+
const paint = () => {
|
|
13
|
+
for (const range of ranges) highlight.delete(range);
|
|
14
|
+
ranges = matchRanges(element, query, selector);
|
|
15
|
+
for (const range of ranges) highlight.add(range);
|
|
16
|
+
};
|
|
17
|
+
paint();
|
|
18
|
+
let frame = 0;
|
|
19
|
+
const observer = new MutationObserver(() => {
|
|
20
|
+
if (frame) return;
|
|
21
|
+
frame = requestAnimationFrame(() => {
|
|
22
|
+
frame = 0;
|
|
23
|
+
paint();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
observer.observe(element, { subtree: true, childList: true, characterData: true });
|
|
27
|
+
return () => {
|
|
28
|
+
observer.disconnect();
|
|
29
|
+
cancelAnimationFrame(frame);
|
|
30
|
+
for (const range of ranges) highlight.delete(range);
|
|
31
|
+
};
|
|
32
|
+
}, [element, query, selector, enabled]);
|
|
33
|
+
return setElement;
|
|
34
|
+
}
|
|
35
|
+
var MATCH_HIGHLIGHT = "sable-match";
|
|
36
|
+
var shared = null;
|
|
37
|
+
function sharedHighlight() {
|
|
38
|
+
if (typeof CSS === "undefined" || !("highlights" in CSS) || typeof Highlight === "undefined") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
shared ??= new Highlight();
|
|
42
|
+
if (CSS.highlights.get(MATCH_HIGHLIGHT) !== shared) CSS.highlights.set(MATCH_HIGHLIGHT, shared);
|
|
43
|
+
return shared;
|
|
44
|
+
}
|
|
45
|
+
function matchRanges(root, query, selector) {
|
|
46
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
47
|
+
if (!needle) return [];
|
|
48
|
+
const scopes = selector ? Array.from(root.querySelectorAll(selector)) : [root];
|
|
49
|
+
const ranges = [];
|
|
50
|
+
for (const scope of scopes) {
|
|
51
|
+
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_TEXT);
|
|
52
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
53
|
+
const haystack = node.data.toLocaleLowerCase();
|
|
54
|
+
if (haystack.length !== node.data.length) continue;
|
|
55
|
+
for (let at = haystack.indexOf(needle); at !== -1; at = haystack.indexOf(needle, at + needle.length)) {
|
|
56
|
+
const range = document.createRange();
|
|
57
|
+
range.setStart(node, at);
|
|
58
|
+
range.setEnd(node, at + needle.length);
|
|
59
|
+
ranges.push(range);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return ranges;
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
MATCH_HIGHLIGHT,
|
|
67
|
+
matchRanges,
|
|
68
|
+
useMatchHighlight
|
|
69
|
+
};
|
|
@@ -112,21 +112,23 @@ function useSmoothWheel({
|
|
|
112
112
|
const activeRef = useRef(active);
|
|
113
113
|
activeRef.current = active;
|
|
114
114
|
const attached = useRef(null);
|
|
115
|
+
const listeners = useRef(null);
|
|
115
116
|
const sync = useCallback(() => {
|
|
116
117
|
const want = activeRef.current ? nodeRef.current : null;
|
|
117
118
|
if (attached.current === want) return;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
was.removeEventListener("scroll", onScroll);
|
|
122
|
-
was.removeEventListener("pointerdown", stop);
|
|
119
|
+
if (attached.current) {
|
|
120
|
+
listeners.current?.abort();
|
|
121
|
+
listeners.current = null;
|
|
123
122
|
stop();
|
|
124
123
|
}
|
|
125
124
|
attached.current = want;
|
|
126
125
|
if (want) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
const controller = new AbortController();
|
|
127
|
+
listeners.current = controller;
|
|
128
|
+
const { signal } = controller;
|
|
129
|
+
want.addEventListener("wheel", onWheel, { passive: false, signal });
|
|
130
|
+
want.addEventListener("scroll", onScroll, { passive: true, signal });
|
|
131
|
+
want.addEventListener("pointerdown", stop, { passive: true, signal });
|
|
130
132
|
}
|
|
131
133
|
}, [onWheel, onScroll, stop]);
|
|
132
134
|
useEffect(sync, [active, sync]);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/motion/Burst.tsx
|
|
4
|
+
import { useRef, useState } from "react";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { motionAttribute, useMotionLevel } from "./MotionProvider.js";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
var DEFAULT_PALETTE = ["pink", "purple", "blue", "orange"];
|
|
9
|
+
function Burst({
|
|
10
|
+
trigger,
|
|
11
|
+
palette = DEFAULT_PALETTE,
|
|
12
|
+
count = 7,
|
|
13
|
+
particle,
|
|
14
|
+
playOnMount = false,
|
|
15
|
+
className,
|
|
16
|
+
motion
|
|
17
|
+
}) {
|
|
18
|
+
const { expressive } = useMotionLevel(motion);
|
|
19
|
+
const [last, setLast] = useState(trigger);
|
|
20
|
+
const [shot, setShot] = useState(playOnMount ? 1 : 0);
|
|
21
|
+
if (!Object.is(trigger, last)) {
|
|
22
|
+
setLast(trigger);
|
|
23
|
+
setShot((n) => n + 1);
|
|
24
|
+
}
|
|
25
|
+
const [done, setDone] = useState(0);
|
|
26
|
+
const landed = useRef({ shot: 0, pieces: 0 });
|
|
27
|
+
if (shot === 0 || shot === done || !expressive || palette.length === 0) return null;
|
|
28
|
+
const places = Math.max(1, Math.round(count));
|
|
29
|
+
const onAnimationEnd = (event) => {
|
|
30
|
+
if (!event.target.classList.contains("sable-burst-dot")) return;
|
|
31
|
+
if (landed.current.shot !== shot) landed.current = { shot, pieces: 0 };
|
|
32
|
+
landed.current.pieces += 1;
|
|
33
|
+
if (landed.current.pieces >= places * 2) setDone(shot);
|
|
34
|
+
};
|
|
35
|
+
const step = 360 / places;
|
|
36
|
+
const scale = particle === void 0 ? 1 : 2.5;
|
|
37
|
+
return /* @__PURE__ */ jsxs(
|
|
38
|
+
"span",
|
|
39
|
+
{
|
|
40
|
+
"aria-hidden": true,
|
|
41
|
+
"data-motion": motionAttribute(motion),
|
|
42
|
+
className: cn("sable-burst [--burst-size:2.25em]", className),
|
|
43
|
+
onAnimationEnd,
|
|
44
|
+
children: [
|
|
45
|
+
particle === void 0 ? /* @__PURE__ */ jsx("span", { className: "sable-burst-ring", "data-palette": palette[0] }) : null,
|
|
46
|
+
Array.from({ length: places }, (_, i) => {
|
|
47
|
+
const angle = i * step - 90;
|
|
48
|
+
return [
|
|
49
|
+
{ angle, reach: 0.95, size: `calc(var(--burst-size) * ${0.14 * scale})`, family: palette[i % palette.length] },
|
|
50
|
+
{
|
|
51
|
+
angle: angle + step / 3,
|
|
52
|
+
reach: 0.75,
|
|
53
|
+
size: `calc(var(--burst-size) * ${0.1 * scale})`,
|
|
54
|
+
family: palette[(i + 1) % palette.length]
|
|
55
|
+
}
|
|
56
|
+
].map((dot, j) => /* @__PURE__ */ jsx(
|
|
57
|
+
"span",
|
|
58
|
+
{
|
|
59
|
+
className: "sable-burst-dot",
|
|
60
|
+
"data-palette": particle === void 0 ? dot.family : void 0,
|
|
61
|
+
"data-particle": particle === void 0 ? void 0 : "",
|
|
62
|
+
style: {
|
|
63
|
+
"--burst-dot-angle": `${dot.angle}deg`,
|
|
64
|
+
"--burst-dot-reach": dot.reach,
|
|
65
|
+
"--burst-dot-size": dot.size
|
|
66
|
+
},
|
|
67
|
+
children: particle
|
|
68
|
+
},
|
|
69
|
+
`${i}-${j}`
|
|
70
|
+
));
|
|
71
|
+
})
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
shot
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
export {
|
|
78
|
+
Burst
|
|
79
|
+
};
|
package/dist/motion/index.js
CHANGED
|
@@ -13,12 +13,14 @@ import { useInView } from "./useInView.js";
|
|
|
13
13
|
import { Reveal } from "./Reveal.js";
|
|
14
14
|
import { TextReveal } from "./TextReveal.js";
|
|
15
15
|
import { Presence } from "./Presence.js";
|
|
16
|
+
import { Burst } from "./Burst.js";
|
|
16
17
|
import {
|
|
17
18
|
startViewTransition,
|
|
18
19
|
supportsViewTransitions,
|
|
19
20
|
ViewTransitionName
|
|
20
21
|
} from "./viewTransition.js";
|
|
21
22
|
export {
|
|
23
|
+
Burst,
|
|
22
24
|
MotionProvider,
|
|
23
25
|
MotionScope,
|
|
24
26
|
Presence,
|
package/dist/presets/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as ThemeManifest } from '../_contract-
|
|
1
|
+
import { T as ThemeManifest } from '../_contract-CDa9-NdB.js';
|
|
2
2
|
|
|
3
3
|
/** An OKLCH colour, lightness 0–1. Extra fields (alpha) ride along untouched. */
|
|
4
4
|
interface OklchColor {
|
|
@@ -31,6 +31,17 @@ declare function fitFillToInk<T extends OklchColor>(fill: T, ink: OklchColor): T
|
|
|
31
31
|
* once, on the colour as picked, then `fitFillToInk` each mode's fill to it.
|
|
32
32
|
*/
|
|
33
33
|
declare function inkPolarity<T extends OklchColor>(color: OklchColor, inks: readonly T[]): T;
|
|
34
|
+
/** A mark's floor against the surfaces it sits on: visibility, not text contrast. */
|
|
35
|
+
declare const MARK_FLOOR = 2;
|
|
36
|
+
/**
|
|
37
|
+
* The mark for a fill: its hue at graphic strength. In light mode the fill is
|
|
38
|
+
* lifted to its hue's mark lightness and its chroma raised 1.3× (never past the
|
|
39
|
+
* gamut, never below its own); in dark mode, where fills are already light, a
|
|
40
|
+
* red is lifted a little and every hue gains 1.15×. A grey tone stays grey.
|
|
41
|
+
* Then it steps back toward the ink until it clears MARK_FLOOR on every surface
|
|
42
|
+
* given, so a pale amber never vanishes into a cream page.
|
|
43
|
+
*/
|
|
44
|
+
declare function markFor<T extends OklchColor>(fill: T, mode: "light" | "dark", surfaces?: readonly OklchColor[]): T;
|
|
34
45
|
/** Fills a theme or preset authors from its brand. Their ink follows the colour as picked. */
|
|
35
46
|
declare const BRAND_FILLS: readonly ["primary", "sidebar-primary", "highlight"];
|
|
36
47
|
/**
|
|
@@ -143,4 +154,4 @@ declare function presetLabelContrast(input: SablePreset): {
|
|
|
143
154
|
unmeasured: string[];
|
|
144
155
|
};
|
|
145
156
|
|
|
146
|
-
export { BRAND_FILLS, LABELLED_FILLS, LABEL_CONTRAST_RULE, type LabelFinding, type OklchColor, PAGE_WIDTH_TOKENS, PRESET_TOKEN_NAMES, type PresetException, STATUS_FILLS, type SablePreset, checkLabelledFills, fitFillToInk, inkFor, inkPolarity, labelContrast, parsePreset, presetCss, presetLabelContrast, presetManifest, validatePreset };
|
|
157
|
+
export { BRAND_FILLS, LABELLED_FILLS, LABEL_CONTRAST_RULE, type LabelFinding, MARK_FLOOR, type OklchColor, PAGE_WIDTH_TOKENS, PRESET_TOKEN_NAMES, type PresetException, STATUS_FILLS, type SablePreset, checkLabelledFills, fitFillToInk, inkFor, inkPolarity, labelContrast, markFor, parsePreset, presetCss, presetLabelContrast, presetManifest, validatePreset };
|
package/dist/presets/index.js
CHANGED
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
LAYERING_TOKENS,
|
|
12
12
|
WORKSPACE_SURFACE_TOKENS,
|
|
13
13
|
DERIVED_EDGE_TOKENS,
|
|
14
|
+
FIELD_TOKENS,
|
|
15
|
+
APP_SHELL_TOKENS,
|
|
16
|
+
MARK_TOKENS,
|
|
14
17
|
TYPE_UI_TOKENS,
|
|
15
18
|
ART_TOKENS,
|
|
16
19
|
PALETTE_TOKENS
|
|
@@ -25,7 +28,9 @@ import {
|
|
|
25
28
|
fitFillToInk,
|
|
26
29
|
inkFor,
|
|
27
30
|
inkPolarity,
|
|
28
|
-
labelContrast
|
|
31
|
+
labelContrast,
|
|
32
|
+
MARK_FLOOR,
|
|
33
|
+
markFor
|
|
29
34
|
} from "../themes/contrast.js";
|
|
30
35
|
var PAGE_WIDTH_TOKENS = [
|
|
31
36
|
"page-inset",
|
|
@@ -39,11 +44,20 @@ var PRESET_TOKEN_NAMES = [.../* @__PURE__ */ new Set([
|
|
|
39
44
|
...SEMANTIC_TOKENS,
|
|
40
45
|
...WORKSPACE_SURFACE_TOKENS.map((name) => `theme-${name}`),
|
|
41
46
|
...DERIVED_EDGE_TOKENS.map((name) => `theme-${name}`),
|
|
47
|
+
// The field's fill and outline: optional — a preset without them keeps outlined fields.
|
|
48
|
+
...FIELD_TOKENS.map((name) => `theme-${name}`),
|
|
49
|
+
// The inset frame's ground: optional — a preset without it keeps the derived step off the rail.
|
|
50
|
+
...APP_SHELL_TOKENS.map((name) => `theme-${name}`),
|
|
51
|
+
// Graphic-strength status colours: optional — a preset without them derives them from its fills.
|
|
52
|
+
...MARK_TOKENS.map((name) => `theme-${name}`),
|
|
42
53
|
// Art direction: optional hooks — a preset without them paints the default art.
|
|
43
54
|
...ART_TOKENS.map((name) => `theme-${name}`),
|
|
44
55
|
...PALETTE_TOKENS.map((name) => `theme-${name}`),
|
|
45
56
|
...WORKSPACE_SURFACE_TOKENS,
|
|
46
57
|
...DERIVED_EDGE_TOKENS,
|
|
58
|
+
...FIELD_TOKENS,
|
|
59
|
+
...APP_SHELL_TOKENS,
|
|
60
|
+
...MARK_TOKENS,
|
|
47
61
|
...RADIUS_TOKENS,
|
|
48
62
|
...MOTION_TOKENS,
|
|
49
63
|
...TYPE_SCALE_TOKENS,
|
|
@@ -226,6 +240,7 @@ export {
|
|
|
226
240
|
BRAND_FILLS,
|
|
227
241
|
LABELLED_FILLS2 as LABELLED_FILLS,
|
|
228
242
|
LABEL_CONTRAST_RULE2 as LABEL_CONTRAST_RULE,
|
|
243
|
+
MARK_FLOOR,
|
|
229
244
|
PAGE_WIDTH_TOKENS,
|
|
230
245
|
PRESET_TOKEN_NAMES,
|
|
231
246
|
STATUS_FILLS,
|
|
@@ -234,6 +249,7 @@ export {
|
|
|
234
249
|
inkFor,
|
|
235
250
|
inkPolarity,
|
|
236
251
|
labelContrast,
|
|
252
|
+
markFor,
|
|
237
253
|
parsePreset,
|
|
238
254
|
presetCss,
|
|
239
255
|
presetLabelContrast,
|