@dorsk/tsumikit 0.78.0 → 0.80.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/dist/components/atoms/Artwork.svelte +5 -3
- package/dist/components/atoms/Badge.svelte +2 -5
- package/dist/components/atoms/Button.svelte +327 -17
- package/dist/components/atoms/Button.svelte.d.ts +4 -1
- package/dist/components/atoms/Card.svelte +160 -12
- package/dist/components/atoms/Checkbox.svelte +181 -3
- package/dist/components/atoms/Gauge.svelte +2 -2
- package/dist/components/atoms/Input.svelte +41 -3
- package/dist/components/atoms/Kbd.svelte +1 -1
- package/dist/components/atoms/Link.svelte +61 -0
- package/dist/components/atoms/Progress.svelte +75 -2
- package/dist/components/atoms/Progress.svelte.d.ts +1 -0
- package/dist/components/atoms/SegmentedProgress.svelte +2 -2
- package/dist/components/atoms/Select.svelte +39 -3
- package/dist/components/atoms/Skeleton.svelte +54 -3
- package/dist/components/atoms/Skeleton.svelte.d.ts +1 -0
- package/dist/components/atoms/Slider.svelte +8 -6
- package/dist/components/atoms/Spinner.svelte +152 -3
- package/dist/components/atoms/Spinner.svelte.d.ts +1 -1
- package/dist/components/atoms/Swatch.svelte +1 -1
- package/dist/components/atoms/Switch.svelte +138 -2
- package/dist/components/atoms/Textarea.svelte +42 -3
- package/dist/components/atoms/Thinking.svelte +130 -0
- package/dist/components/atoms/Thinking.svelte.d.ts +15 -0
- package/dist/components/layouts/AppShell.svelte +6 -6
- package/dist/components/layouts/MasterDetail.svelte +3 -3
- package/dist/components/layouts/NavBar.svelte +4 -4
- package/dist/components/layouts/NavSection.svelte +1 -1
- package/dist/components/layouts/ResizablePanel.svelte +7 -7
- package/dist/components/layouts/TabBar.svelte +2 -2
- package/dist/components/molecules/Accordion.svelte +2 -2
- package/dist/components/molecules/AttachmentList.svelte +2 -2
- package/dist/components/molecules/CapBar.svelte +2 -2
- package/dist/components/molecules/CodeBlock.svelte +5 -5
- package/dist/components/molecules/Combobox.svelte +3 -3
- package/dist/components/molecules/CopyButton.svelte +146 -5
- package/dist/components/molecules/Drawer.svelte +8 -8
- package/dist/components/molecules/EmojiPicker.svelte +1 -1
- package/dist/components/molecules/Field.svelte +55 -1
- package/dist/components/molecules/FileButton.svelte +20 -6
- package/dist/components/molecules/FilterInput.svelte +4 -4
- package/dist/components/molecules/GitRef.svelte +2 -2
- package/dist/components/molecules/GlyphStack.svelte +21 -3
- package/dist/components/molecules/InputGroup.svelte +3 -3
- package/dist/components/molecules/LookPicker.svelte +87 -0
- package/dist/components/molecules/LookPicker.svelte.d.ts +17 -0
- package/dist/components/molecules/Modal.svelte +5 -5
- package/dist/components/molecules/MotionSettings.svelte +166 -0
- package/dist/components/molecules/MotionSettings.svelte.d.ts +18 -0
- package/dist/components/molecules/OptionButton.svelte +8 -3
- package/dist/components/molecules/Pagination.svelte +3 -1
- package/dist/components/molecules/Popover.svelte +18 -11
- package/dist/components/molecules/Prose.svelte +6 -6
- package/dist/components/molecules/RadialMenu.svelte +3 -3
- package/dist/components/molecules/RadioGroup.svelte +67 -4
- package/dist/components/molecules/RichSelect.svelte +6 -4
- package/dist/components/molecules/SectionHeader.svelte +1 -1
- package/dist/components/molecules/SeekSlider.svelte +6 -6
- package/dist/components/molecules/SegmentedControl.svelte +7 -7
- package/dist/components/molecules/SortableList.svelte +2 -2
- package/dist/components/molecules/SplitButton.svelte +1 -1
- package/dist/components/molecules/Tabs.svelte +160 -7
- package/dist/components/molecules/ThemePicker.svelte +1 -1
- package/dist/components/molecules/Timestamp.svelte +1 -1
- package/dist/components/molecules/Toggle.svelte +5 -3
- package/dist/components/molecules/Tooltip.svelte +2 -2
- package/dist/components/molecules/VolumeSlider.svelte +3 -3
- package/dist/components/organisms/ConversationFeed.svelte +1 -1
- package/dist/components/organisms/ConversationPanel.svelte +3 -3
- package/dist/components/organisms/DataTable.svelte +18 -16
- package/dist/fx.d.ts +149 -0
- package/dist/fx.js +111 -0
- package/dist/fx.md +58 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +8 -2
- package/dist/looks/README.md +101 -0
- package/dist/looks/depth.css +939 -0
- package/dist/looks/editorial.css +545 -0
- package/dist/looks/tactile.css +871 -0
- package/dist/pointer.d.ts +3 -0
- package/dist/pointer.js +40 -0
- package/dist/stores/fx.svelte.d.ts +17 -0
- package/dist/stores/fx.svelte.js +64 -0
- package/dist/stores/theme.svelte.d.ts +8 -2
- package/dist/stores/theme.svelte.js +33 -7
- package/dist/styles/themes.css +249 -249
- package/dist/styles/tokens.css +37 -2
- package/dist/theme-mode.d.ts +31 -0
- package/dist/theme-mode.js +19 -0
- package/package.json +3 -2
package/dist/pointer.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Sets `--pointer-x` / `--pointer-y` (px, box-relative) on the hovered
|
|
2
|
+
* `[data-tsu]` element and its `[data-tsu]` ancestors, mouse only. */
|
|
3
|
+
export function trackPointer(doc = globalThis.document) {
|
|
4
|
+
if (!doc)
|
|
5
|
+
return () => { };
|
|
6
|
+
const win = doc.defaultView;
|
|
7
|
+
let last = null;
|
|
8
|
+
let frame = 0;
|
|
9
|
+
const flush = () => {
|
|
10
|
+
frame = 0;
|
|
11
|
+
const e = last;
|
|
12
|
+
last = null;
|
|
13
|
+
if (!e)
|
|
14
|
+
return;
|
|
15
|
+
let el = e.target?.closest?.('[data-tsu]');
|
|
16
|
+
while (el) {
|
|
17
|
+
const r = el.getBoundingClientRect();
|
|
18
|
+
el.style.setProperty('--pointer-x', `${e.clientX - r.left}px`);
|
|
19
|
+
el.style.setProperty('--pointer-y', `${e.clientY - r.top}px`);
|
|
20
|
+
el = el.parentElement?.closest('[data-tsu]');
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const move = (e) => {
|
|
24
|
+
if (e.pointerType !== 'mouse')
|
|
25
|
+
return;
|
|
26
|
+
last = e;
|
|
27
|
+
if (!win)
|
|
28
|
+
flush();
|
|
29
|
+
else if (!frame)
|
|
30
|
+
frame = win.requestAnimationFrame(flush);
|
|
31
|
+
};
|
|
32
|
+
doc.addEventListener('pointermove', move, { passive: true });
|
|
33
|
+
return () => {
|
|
34
|
+
doc.removeEventListener('pointermove', move);
|
|
35
|
+
if (frame)
|
|
36
|
+
win?.cancelAnimationFrame(frame);
|
|
37
|
+
frame = 0;
|
|
38
|
+
last = null;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type FxFamily, type FxSettings, type FxVariant } from '../fx';
|
|
2
|
+
export declare const FX_PREPAINT: string;
|
|
3
|
+
declare class Fx {
|
|
4
|
+
settings: FxSettings;
|
|
5
|
+
onchange?: (settings: FxSettings) => void;
|
|
6
|
+
constructor();
|
|
7
|
+
get<F extends FxFamily>(family: F): FxVariant<F>;
|
|
8
|
+
set<F extends FxFamily>(family: F, variant: string): void;
|
|
9
|
+
reset(): void;
|
|
10
|
+
get isDefault(): boolean;
|
|
11
|
+
/** Replay settings an app persisted itself, without echoing through `onchange`. */
|
|
12
|
+
hydrate(settings: Partial<FxSettings>): void;
|
|
13
|
+
private commit;
|
|
14
|
+
private apply;
|
|
15
|
+
}
|
|
16
|
+
export declare const fx: Fx;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { browser } from '../env';
|
|
2
|
+
import { DEFAULT_FX, FX_FAMILIES, fxAttr, fxDiff, fxPrepaint, isFxVariant, parseFx, } from '../fx';
|
|
3
|
+
import { readStorage, writeStorage } from './storage';
|
|
4
|
+
// Until something is saved or set, <html> is left untouched so attributes an
|
|
5
|
+
// app wrote itself win.
|
|
6
|
+
const KEY = 'tsumikit-fx';
|
|
7
|
+
export const FX_PREPAINT = fxPrepaint(KEY);
|
|
8
|
+
class Fx {
|
|
9
|
+
settings = $state({ ...DEFAULT_FX });
|
|
10
|
+
onchange;
|
|
11
|
+
constructor() {
|
|
12
|
+
if (!browser)
|
|
13
|
+
return;
|
|
14
|
+
const raw = readStorage(KEY);
|
|
15
|
+
if (!raw)
|
|
16
|
+
return;
|
|
17
|
+
try {
|
|
18
|
+
this.settings = parseFx(JSON.parse(raw));
|
|
19
|
+
}
|
|
20
|
+
catch { }
|
|
21
|
+
this.apply();
|
|
22
|
+
}
|
|
23
|
+
get(family) {
|
|
24
|
+
return this.settings[family];
|
|
25
|
+
}
|
|
26
|
+
set(family, variant) {
|
|
27
|
+
if (!isFxVariant(family, variant))
|
|
28
|
+
return;
|
|
29
|
+
this.settings = { ...this.settings, [family]: variant };
|
|
30
|
+
this.commit();
|
|
31
|
+
}
|
|
32
|
+
reset() {
|
|
33
|
+
this.settings = { ...DEFAULT_FX };
|
|
34
|
+
this.commit();
|
|
35
|
+
}
|
|
36
|
+
get isDefault() {
|
|
37
|
+
return Object.keys(fxDiff(this.settings)).length === 0;
|
|
38
|
+
}
|
|
39
|
+
/** Replay settings an app persisted itself, without echoing through `onchange`. */
|
|
40
|
+
hydrate(settings) {
|
|
41
|
+
this.settings = parseFx(settings);
|
|
42
|
+
this.apply();
|
|
43
|
+
if (browser)
|
|
44
|
+
writeStorage(KEY, JSON.stringify(fxDiff(this.settings)));
|
|
45
|
+
}
|
|
46
|
+
commit() {
|
|
47
|
+
this.apply();
|
|
48
|
+
if (browser)
|
|
49
|
+
writeStorage(KEY, JSON.stringify(fxDiff(this.settings)));
|
|
50
|
+
this.onchange?.(this.settings);
|
|
51
|
+
}
|
|
52
|
+
apply() {
|
|
53
|
+
if (!browser)
|
|
54
|
+
return;
|
|
55
|
+
const root = document.documentElement;
|
|
56
|
+
for (const f of FX_FAMILIES) {
|
|
57
|
+
if (this.settings[f] === DEFAULT_FX[f])
|
|
58
|
+
root.removeAttribute(fxAttr(f));
|
|
59
|
+
else
|
|
60
|
+
root.setAttribute(fxAttr(f), this.settings[f]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export const fx = new Fx();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type SlotOf, type ThemeChoice, type ThemePreference } from '../theme-mode';
|
|
1
|
+
import { type LookId, type SlotOf, type ThemeChoice, type ThemePreference } from '../theme-mode';
|
|
2
2
|
export declare const THEMES: readonly [{
|
|
3
3
|
readonly id: "light";
|
|
4
4
|
readonly label: "Light";
|
|
@@ -186,6 +186,8 @@ export declare const THEMES: readonly [{
|
|
|
186
186
|
readonly themeColor: "#3f3f3f";
|
|
187
187
|
readonly mode: "dark";
|
|
188
188
|
}];
|
|
189
|
+
/** Pre-paint script for the built-in themes; inline it in <head>. */
|
|
190
|
+
export declare const THEME_PREPAINT: string;
|
|
189
191
|
export type Mode = (typeof THEMES)[number]['id'];
|
|
190
192
|
export type ThemeMode = (typeof THEMES)[number]['mode'];
|
|
191
193
|
export type ThemeId = Mode | (string & {});
|
|
@@ -222,6 +224,8 @@ declare class Theme {
|
|
|
222
224
|
setDefault(id: ThemeId): void;
|
|
223
225
|
private resolve;
|
|
224
226
|
private read;
|
|
227
|
+
/** The active structural look; `default` when none is set. */
|
|
228
|
+
get look(): LookId;
|
|
225
229
|
private paint;
|
|
226
230
|
private persist;
|
|
227
231
|
private apply;
|
|
@@ -234,8 +238,10 @@ declare class Theme {
|
|
|
234
238
|
/** A picker choice: `auto`, or a theme id, which also becomes its slot's
|
|
235
239
|
* remembered theme. An unregistered id is ignored. */
|
|
236
240
|
choose(choice: string): ThemePreference;
|
|
241
|
+
/** Pick a look; unknown ids fall back to the default look. */
|
|
242
|
+
setLook(look: string): ThemePreference;
|
|
237
243
|
/** Replay a preference an app persisted itself, without echoing it back
|
|
238
|
-
* through `onchange`. */
|
|
244
|
+
* through `onchange`. A preference without `look` keeps the current one. */
|
|
239
245
|
hydrate(pref: ThemePreference): void;
|
|
240
246
|
}
|
|
241
247
|
export declare const theme: Theme;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { browser } from '../env';
|
|
2
|
-
import { AUTO_THEME, chooseTheme, DEFAULT_THEME_PREFERENCE, preferenceFrom, resolveTheme, } from '../theme-mode';
|
|
2
|
+
import { AUTO_THEME, chooseTheme, DEFAULT_LOOK, DEFAULT_THEME_PREFERENCE, parseLook, preferenceFrom, resolveTheme, themePrepaint, } from '../theme-mode';
|
|
3
3
|
import { readStorage, writeStorage } from './storage';
|
|
4
4
|
// Theme registry. Built-ins live in THEMES (+ one [data-theme="id"] block in
|
|
5
5
|
// styles/themes.css); consumers append their own with theme.register() and ship
|
|
@@ -8,7 +8,8 @@ import { readStorage, writeStorage } from './storage';
|
|
|
8
8
|
// light/dark sections.
|
|
9
9
|
//
|
|
10
10
|
// `tsumikit-theme` holds a {mode,light,dark} blob; a bare theme id there is a
|
|
11
|
-
// legacy value and migrates through `preferenceFrom`.
|
|
11
|
+
// legacy value and migrates through `preferenceFrom`. The blob also carries
|
|
12
|
+
// `look` when it is not the default.
|
|
12
13
|
const KEY = 'tsumikit-theme';
|
|
13
14
|
const SCHEME_QUERY = '(prefers-color-scheme: dark)';
|
|
14
15
|
export const THEMES = [
|
|
@@ -67,6 +68,8 @@ export const THEMES = [
|
|
|
67
68
|
{ id: 'espresso', label: 'Espresso', icon: '◉', themeColor: '#463a31', mode: 'dark' },
|
|
68
69
|
{ id: 'zenburn', label: 'Zenburn', icon: 'Z', themeColor: '#3f3f3f', mode: 'dark' },
|
|
69
70
|
];
|
|
71
|
+
/** Pre-paint script for the built-in themes; inline it in <head>. */
|
|
72
|
+
export const THEME_PREPAINT = themePrepaint(KEY, THEMES);
|
|
70
73
|
const FALLBACK_ICON = '◈';
|
|
71
74
|
class Theme {
|
|
72
75
|
current = $state('dark');
|
|
@@ -142,9 +145,14 @@ class Theme {
|
|
|
142
145
|
blob = parsed;
|
|
143
146
|
}
|
|
144
147
|
catch { }
|
|
145
|
-
|
|
148
|
+
const pref = preferenceFrom(blob
|
|
146
149
|
? { themeMode: blob.mode, lightTheme: blob.light, darkTheme: blob.dark }
|
|
147
150
|
: { theme: this.saved }, this.slotOf, seed);
|
|
151
|
+
return withLook(pref, blob?.look);
|
|
152
|
+
}
|
|
153
|
+
/** The active structural look; `default` when none is set. */
|
|
154
|
+
get look() {
|
|
155
|
+
return parseLook(this.pref.look);
|
|
148
156
|
}
|
|
149
157
|
paint() {
|
|
150
158
|
this.current = this.resolved;
|
|
@@ -159,7 +167,13 @@ class Theme {
|
|
|
159
167
|
apply() {
|
|
160
168
|
if (!browser)
|
|
161
169
|
return;
|
|
162
|
-
document.documentElement
|
|
170
|
+
const root = document.documentElement;
|
|
171
|
+
root.setAttribute('data-theme', this.current);
|
|
172
|
+
root.setAttribute('data-mode', this.option.mode);
|
|
173
|
+
if (this.look === DEFAULT_LOOK)
|
|
174
|
+
root.removeAttribute('data-look');
|
|
175
|
+
else
|
|
176
|
+
root.setAttribute('data-look', this.look);
|
|
163
177
|
const color = this.option.themeColor;
|
|
164
178
|
if (color)
|
|
165
179
|
document
|
|
@@ -194,12 +208,24 @@ class Theme {
|
|
|
194
208
|
this.persist();
|
|
195
209
|
return this.pref;
|
|
196
210
|
}
|
|
211
|
+
/** Pick a look; unknown ids fall back to the default look. */
|
|
212
|
+
setLook(look) {
|
|
213
|
+
this.pref = withLook(this.pref, look);
|
|
214
|
+
this.apply();
|
|
215
|
+
this.persist();
|
|
216
|
+
return this.pref;
|
|
217
|
+
}
|
|
197
218
|
/** Replay a preference an app persisted itself, without echoing it back
|
|
198
|
-
* through `onchange`. */
|
|
219
|
+
* through `onchange`. A preference without `look` keeps the current one. */
|
|
199
220
|
hydrate(pref) {
|
|
200
|
-
this.pref = pref;
|
|
201
|
-
this.saved = JSON.stringify(pref);
|
|
221
|
+
this.pref = withLook(pref, 'look' in pref ? pref.look : this.pref.look);
|
|
222
|
+
this.saved = JSON.stringify(this.pref);
|
|
202
223
|
this.paint();
|
|
203
224
|
}
|
|
204
225
|
}
|
|
226
|
+
function withLook(pref, look) {
|
|
227
|
+
const { look: _, ...rest } = pref;
|
|
228
|
+
const id = parseLook(look);
|
|
229
|
+
return id === DEFAULT_LOOK ? rest : { ...rest, look: id };
|
|
230
|
+
}
|
|
205
231
|
export const theme = new Theme();
|