@rokkit/app 1.1.18 → 1.2.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/SkinSwitcherToggle.svelte.d.ts +16 -0
- package/dist/components/TableOfContents.svelte.d.ts +8 -0
- package/dist/components/ThemeSwitcherToggle.svelte.d.ts +4 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/skin-switcher.d.ts +10 -0
- package/dist/types/theme-switcher.d.ts +68 -0
- package/dist/utils/color-mode.svelte.d.ts +38 -0
- package/package.json +12 -10
- package/src/components/TableOfContents.svelte +17 -15
- package/src/types/skin-switcher.ts +4 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
skins?: Array<string | {
|
|
3
|
+
name: string;
|
|
4
|
+
label?: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
}>;
|
|
7
|
+
labels?: Record<string, string>;
|
|
8
|
+
showLabels?: boolean;
|
|
9
|
+
size?: 'sm' | 'md' | 'lg';
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
class?: string;
|
|
12
|
+
onchange?: (skin: string) => void;
|
|
13
|
+
};
|
|
14
|
+
declare const SkinSwitcherToggle: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
15
|
+
type SkinSwitcherToggle = ReturnType<typeof SkinSwitcherToggle>;
|
|
16
|
+
export default SkinSwitcherToggle;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ThemeSwitcherToggleProps } from '../types/theme-switcher.js';
|
|
2
|
+
declare const ThemeSwitcherToggle: import("svelte").Component<ThemeSwitcherToggleProps, {}, "">;
|
|
3
|
+
type ThemeSwitcherToggle = ReturnType<typeof ThemeSwitcherToggle>;
|
|
4
|
+
export default ThemeSwitcherToggle;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type SkinSwitcherOption = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function buildSkinSwitcherOptions(skins: Array<string | {
|
|
7
|
+
name: string;
|
|
8
|
+
label?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
}>, labels?: Record<string, string>): SkinSwitcherOption[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ThemeSwitcherToggle Types
|
|
3
|
+
*
|
|
4
|
+
* Types and defaults for the theme mode switcher component.
|
|
5
|
+
*/
|
|
6
|
+
import type { ToggleItemSnippet } from '@rokkit/ui';
|
|
7
|
+
import type { ColorMode } from '../utils/color-mode.svelte.js';
|
|
8
|
+
export interface ThemeSwitcherIcons {
|
|
9
|
+
system?: string;
|
|
10
|
+
light?: string;
|
|
11
|
+
dark?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare const defaultThemeSwitcherIcons: Required<ThemeSwitcherIcons>;
|
|
14
|
+
export interface ThemeSwitcherOption {
|
|
15
|
+
value: ColorMode;
|
|
16
|
+
label: string;
|
|
17
|
+
icon: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
export interface ThemeSwitcherLabels {
|
|
21
|
+
system?: string;
|
|
22
|
+
light?: string;
|
|
23
|
+
dark?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build toggle options from icons, modes, and labels
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildThemeSwitcherOptions(icons: Required<ThemeSwitcherIcons>, modes: ColorMode[], labels?: ThemeSwitcherLabels): ThemeSwitcherOption[];
|
|
29
|
+
/**
|
|
30
|
+
* Visual variant.
|
|
31
|
+
* - `'single'` — one icon-only button that cycles between light and dark on click.
|
|
32
|
+
* System mode is not part of the cycle. The icon shows the mode you'd switch *to*.
|
|
33
|
+
* - `'pair'` — two buttons: light and dark. Equivalent to `includeSystem={false}`
|
|
34
|
+
* for the legacy triad UI.
|
|
35
|
+
* - `'triad'` — three buttons: system, light, dark. Default.
|
|
36
|
+
*/
|
|
37
|
+
export type ThemeSwitcherVariant = 'single' | 'pair' | 'triad';
|
|
38
|
+
export interface ThemeSwitcherToggleProps {
|
|
39
|
+
/** Visual variant. Default: 'triad'. */
|
|
40
|
+
variant?: ThemeSwitcherVariant;
|
|
41
|
+
/**
|
|
42
|
+
* Which modes to show. Only honored for `variant: 'triad'`.
|
|
43
|
+
* Default: `['system', 'light', 'dark']`.
|
|
44
|
+
*/
|
|
45
|
+
modes?: ColorMode[];
|
|
46
|
+
/**
|
|
47
|
+
* Whether to include system mode. Default: true. Shortcut for filtering 'system'
|
|
48
|
+
* from modes. Only honored for `variant: 'triad'`. For `'pair'` and `'single'`
|
|
49
|
+
* system is never included.
|
|
50
|
+
*/
|
|
51
|
+
includeSystem?: boolean;
|
|
52
|
+
/** Override icons per mode */
|
|
53
|
+
icons?: ThemeSwitcherIcons;
|
|
54
|
+
/** Override labels per mode. Merged over messages.mode */
|
|
55
|
+
labels?: ThemeSwitcherLabels;
|
|
56
|
+
/** Show text labels alongside icons. Ignored for `variant: 'single'`. Default: false */
|
|
57
|
+
showLabels?: boolean;
|
|
58
|
+
/** Size variant. Default: 'sm' */
|
|
59
|
+
size?: 'sm' | 'md' | 'lg';
|
|
60
|
+
/** Disabled state */
|
|
61
|
+
disabled?: boolean;
|
|
62
|
+
/** Additional CSS classes */
|
|
63
|
+
class?: string;
|
|
64
|
+
/** Custom snippet for rendering toggle items (only honored for `'pair'` / `'triad'`) */
|
|
65
|
+
item?: ToggleItemSnippet;
|
|
66
|
+
/** Called when mode changes */
|
|
67
|
+
onchange?: (mode: ColorMode) => void;
|
|
68
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color Mode Manager
|
|
3
|
+
*
|
|
4
|
+
* Bridges three-mode UI (system/light/dark) with vibe's two-mode store (light/dark).
|
|
5
|
+
* Resolves 'system' to actual OS preference via matchMedia.
|
|
6
|
+
*/
|
|
7
|
+
export type ColorMode = 'system' | 'light' | 'dark';
|
|
8
|
+
export type ResolvedMode = 'light' | 'dark';
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a ColorMode to an actual light/dark value.
|
|
11
|
+
* When 'system', queries the OS preference via matchMedia.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveMode(mode: ColorMode): ResolvedMode;
|
|
14
|
+
/**
|
|
15
|
+
* Theme target interface — anything with a settable mode property.
|
|
16
|
+
* Compatible with the vibe singleton from @rokkit/states.
|
|
17
|
+
*/
|
|
18
|
+
interface ThemeTarget {
|
|
19
|
+
mode: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reactive color mode manager that tracks system/light/dark,
|
|
23
|
+
* resolves to actual light/dark, and syncs to a theme target (e.g. vibe).
|
|
24
|
+
*/
|
|
25
|
+
export declare class ColorModeManager {
|
|
26
|
+
#private;
|
|
27
|
+
constructor(target: ThemeTarget, initialMode?: ColorMode);
|
|
28
|
+
get mode(): ColorMode;
|
|
29
|
+
set mode(value: ColorMode);
|
|
30
|
+
get resolved(): ResolvedMode;
|
|
31
|
+
/**
|
|
32
|
+
* Start listening for OS preference changes.
|
|
33
|
+
* Returns a cleanup function to stop listening.
|
|
34
|
+
* Call in onMount or $effect.root.
|
|
35
|
+
*/
|
|
36
|
+
listen(): () => void;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "App-level controls for Rokkit applications - theme management and UI chrome",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -11,41 +11,43 @@
|
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
13
13
|
"svelte": "./src/index.ts",
|
|
14
|
-
"types": "./
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
15
|
"exports": {
|
|
16
16
|
".": {
|
|
17
|
-
"types": "./
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
18
|
"svelte": "./src/index.ts",
|
|
19
19
|
"default": "./src/index.ts"
|
|
20
20
|
},
|
|
21
21
|
"./types": {
|
|
22
|
-
"types": "./
|
|
22
|
+
"types": "./dist/types/index.d.ts",
|
|
23
23
|
"default": "./src/types/index.ts"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
27
|
"src",
|
|
28
|
+
"dist/**/*.d.ts",
|
|
28
29
|
"README.md",
|
|
29
30
|
"LICENSE"
|
|
30
31
|
],
|
|
31
32
|
"scripts": {
|
|
32
|
-
"prepublishOnly": "cp ../../LICENSE .",
|
|
33
|
+
"prepublishOnly": "cp ../../LICENSE . && bun run build",
|
|
33
34
|
"postpublish": "rm -f LICENSE",
|
|
34
35
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
35
36
|
"test": "vitest run",
|
|
36
37
|
"test:watch": "vitest",
|
|
37
|
-
"build": "
|
|
38
|
+
"build": "svelte-package -i src -o dist"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
|
-
"@rokkit/actions": "1.
|
|
41
|
-
"@rokkit/core": "1.
|
|
42
|
-
"@rokkit/states": "1.
|
|
43
|
-
"@rokkit/ui": "1.
|
|
41
|
+
"@rokkit/actions": "1.2.0",
|
|
42
|
+
"@rokkit/core": "1.2.0",
|
|
43
|
+
"@rokkit/states": "1.2.0",
|
|
44
|
+
"@rokkit/ui": "1.2.0"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
|
46
47
|
"svelte": "^5.0.0"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@sveltejs/package": "^2.5.8",
|
|
49
51
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
50
52
|
"@testing-library/jest-dom": "^6.9.1",
|
|
51
53
|
"@testing-library/svelte": "^5.3.1",
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
// @ts-nocheck
|
|
1
|
+
<script lang="ts">
|
|
3
2
|
import { onMount } from 'svelte'
|
|
4
3
|
import { keyboard } from '@rokkit/actions'
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
type Heading = { id: string; text: string; level: string }
|
|
7
6
|
|
|
8
|
-
let
|
|
7
|
+
let { container = 'main-content' }: { container?: string } = $props()
|
|
8
|
+
|
|
9
|
+
let headings = $state<Heading[]>([])
|
|
9
10
|
let activeId = $state('')
|
|
10
11
|
let focusedIndex = $state(0)
|
|
11
|
-
let navEl = $state(null)
|
|
12
|
-
let observer = null
|
|
13
|
-
let scrollLockTimer = null
|
|
12
|
+
let navEl = $state<HTMLElement | null>(null)
|
|
13
|
+
let observer: IntersectionObserver | null = null
|
|
14
|
+
let scrollLockTimer: ReturnType<typeof setTimeout> | null = null
|
|
14
15
|
|
|
15
|
-
function slugify(text) {
|
|
16
|
+
function slugify(text: string | null) {
|
|
16
17
|
return (text ?? '')
|
|
17
18
|
.toLowerCase()
|
|
18
19
|
.trim()
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
observer?.disconnect()
|
|
41
42
|
const main = getContainer()
|
|
42
43
|
if (!main || headings.length === 0) return
|
|
43
|
-
|
|
44
|
+
const obs = new IntersectionObserver(
|
|
44
45
|
(entries) => {
|
|
45
46
|
const visible = entries
|
|
46
47
|
.filter((e) => e.isIntersecting)
|
|
@@ -49,17 +50,18 @@
|
|
|
49
50
|
},
|
|
50
51
|
{ root: main, rootMargin: '-5% 0px -70% 0px' }
|
|
51
52
|
)
|
|
53
|
+
observer = obs
|
|
52
54
|
headings.forEach(({ id }) => {
|
|
53
55
|
const el = document.getElementById(id)
|
|
54
|
-
if (el)
|
|
56
|
+
if (el) obs.observe(el)
|
|
55
57
|
})
|
|
56
58
|
}
|
|
57
59
|
|
|
58
|
-
function scrollToHeading(id) {
|
|
59
|
-
const el = document.getElementById(id)
|
|
60
|
+
function scrollToHeading(id: string | undefined) {
|
|
61
|
+
const el = document.getElementById(id ?? '')
|
|
60
62
|
const main = getContainer()
|
|
61
63
|
if (!el || !main) return
|
|
62
|
-
clearTimeout(scrollLockTimer)
|
|
64
|
+
clearTimeout(scrollLockTimer ?? undefined)
|
|
63
65
|
scrollLockTimer = setTimeout(() => {
|
|
64
66
|
scrollLockTimer = null
|
|
65
67
|
}, 1000)
|
|
@@ -74,7 +76,7 @@
|
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
function getItems() {
|
|
77
|
-
return navEl?.querySelectorAll('[data-toc-item]') ?? []
|
|
79
|
+
return navEl?.querySelectorAll<HTMLElement>('[data-toc-item]') ?? []
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
function handlePrevious() {
|
|
@@ -109,7 +111,7 @@
|
|
|
109
111
|
observe()
|
|
110
112
|
return () => {
|
|
111
113
|
observer?.disconnect()
|
|
112
|
-
clearTimeout(scrollLockTimer)
|
|
114
|
+
clearTimeout(scrollLockTimer ?? undefined)
|
|
113
115
|
}
|
|
114
116
|
})
|
|
115
117
|
</script>
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
// A `type` alias (not an `interface`) so it satisfies the
|
|
2
|
+
// `Record<string, unknown>` index signature that Toggle's `ToggleItem`
|
|
3
|
+
// expects — TS interfaces don't implicitly carry an index signature.
|
|
4
|
+
export type SkinSwitcherOption = {
|
|
2
5
|
value: string
|
|
3
6
|
label: string
|
|
4
7
|
icon?: string
|