@rokkit/ui 1.0.0-next.99 → 1.0.1
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 +159 -1
- package/package.json +52 -53
- package/src/MarkdownRenderer.svelte +106 -0
- package/src/components/AlertList.svelte +59 -0
- package/src/components/Avatar.svelte +68 -0
- package/src/components/Badge.svelte +57 -0
- package/src/components/BreadCrumbs.svelte +94 -0
- package/src/components/Button.svelte +91 -0
- package/src/components/ButtonGroup.svelte +9 -0
- package/src/components/Card.svelte +71 -0
- package/src/components/Carousel.svelte +169 -0
- package/src/components/Code.svelte +189 -0
- package/src/components/Connector.svelte +46 -0
- package/src/components/Divider.svelte +24 -0
- package/src/components/Dropdown.svelte +202 -0
- package/src/components/FloatingAction.svelte +367 -0
- package/src/components/FloatingNavigation.svelte +256 -0
- package/src/components/Grid.svelte +128 -0
- package/src/components/ItemContent.svelte +25 -0
- package/src/components/LazyTree.svelte +171 -0
- package/src/components/List.svelte +224 -0
- package/src/components/Menu.svelte +270 -0
- package/src/components/Message.svelte +75 -0
- package/src/components/MultiSelect.svelte +367 -0
- package/src/components/PaletteManager.svelte +360 -0
- package/src/components/Pill.svelte +83 -0
- package/src/components/ProgressBar.svelte +31 -0
- package/src/components/Range.svelte +346 -0
- package/src/components/Rating.svelte +115 -0
- package/src/components/Reveal.svelte +46 -0
- package/src/components/SearchFilter.svelte +88 -0
- package/src/components/Select.svelte +424 -0
- package/src/components/Shine.svelte +87 -0
- package/src/components/Stack.svelte +38 -0
- package/src/components/StatusList.svelte +18 -0
- package/src/components/Stepper.svelte +174 -0
- package/src/components/Swatch.svelte +102 -0
- package/src/components/Switch.svelte +71 -0
- package/src/components/Table.svelte +245 -0
- package/src/components/Tabs.svelte +202 -0
- package/src/components/Tilt.svelte +68 -0
- package/src/components/Timeline.svelte +61 -0
- package/src/components/Toggle.svelte +93 -0
- package/src/components/Toolbar.svelte +306 -0
- package/src/components/ToolbarGroup.svelte +17 -0
- package/src/components/Tooltip.svelte +121 -0
- package/src/components/Tree.svelte +143 -0
- package/src/components/UploadFileStatus.svelte +102 -0
- package/src/components/UploadProgress.svelte +127 -0
- package/src/components/UploadTarget.svelte +126 -0
- package/src/components/index.ts +48 -0
- package/src/index.ts +59 -0
- package/src/markdown-plugin.ts +12 -0
- package/src/types/button.ts +86 -0
- package/src/types/code.ts +46 -0
- package/src/types/floating-action.ts +123 -0
- package/src/types/floating-navigation.ts +80 -0
- package/src/types/index.ts +58 -0
- package/src/types/list.ts +200 -0
- package/src/types/menu.ts +95 -0
- package/src/types/palette.ts +160 -0
- package/src/types/range.ts +51 -0
- package/src/types/search-filter.ts +67 -0
- package/src/types/select.ts +176 -0
- package/src/types/switch.ts +68 -0
- package/src/types/table.ts +219 -0
- package/src/types/tabs.ts +103 -0
- package/src/types/timeline.ts +53 -0
- package/src/types/toggle.ts +68 -0
- package/src/types/toolbar.ts +167 -0
- package/src/types/tooltip.ts +21 -0
- package/src/types/tree.ts +250 -0
- package/src/types/upload-file-status.ts +45 -0
- package/src/types/upload-progress.ts +111 -0
- package/src/types/upload-target.ts +71 -0
- package/src/utils/palette.ts +618 -0
- package/src/utils/shiki.ts +114 -0
- package/src/utils/upload.js +145 -0
- package/LICENSE +0 -21
- package/src/index.js +0 -8
- package/src/wrappers.js +0 -2
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shiki syntax highlighting utility
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createHighlighter, type Highlighter, type BundledLanguage, type BundledTheme } from 'shiki'
|
|
6
|
+
|
|
7
|
+
let highlighter: Highlighter | null = null
|
|
8
|
+
let isInitializing = false
|
|
9
|
+
let initPromise: Promise<Highlighter> | null = null
|
|
10
|
+
|
|
11
|
+
// Supported languages for the application
|
|
12
|
+
const SUPPORTED_LANGUAGES: BundledLanguage[] = [
|
|
13
|
+
'svelte',
|
|
14
|
+
'javascript',
|
|
15
|
+
'typescript',
|
|
16
|
+
'css',
|
|
17
|
+
'html',
|
|
18
|
+
'json',
|
|
19
|
+
'bash',
|
|
20
|
+
'shell',
|
|
21
|
+
'markdown',
|
|
22
|
+
'yaml',
|
|
23
|
+
'sql'
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
// Available themes
|
|
27
|
+
const THEMES: BundledTheme[] = ['github-light', 'github-dark']
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Initialize Shiki highlighter (singleton)
|
|
31
|
+
*/
|
|
32
|
+
function initializeHighlighter(): Promise<Highlighter> {
|
|
33
|
+
if (highlighter) return Promise.resolve(highlighter)
|
|
34
|
+
|
|
35
|
+
if (isInitializing && initPromise) {
|
|
36
|
+
return initPromise
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
isInitializing = true
|
|
40
|
+
|
|
41
|
+
initPromise = createHighlighter({
|
|
42
|
+
themes: THEMES,
|
|
43
|
+
langs: SUPPORTED_LANGUAGES
|
|
44
|
+
})
|
|
45
|
+
.then((hl: Highlighter) => {
|
|
46
|
+
highlighter = hl
|
|
47
|
+
isInitializing = false
|
|
48
|
+
return hl
|
|
49
|
+
})
|
|
50
|
+
.catch((error: Error) => {
|
|
51
|
+
isInitializing = false
|
|
52
|
+
initPromise = null
|
|
53
|
+
throw error
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return initPromise
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface HighlightOptions {
|
|
60
|
+
/** Language for syntax highlighting */
|
|
61
|
+
lang?: BundledLanguage | string
|
|
62
|
+
/** Theme to use (defaults based on user preference) */
|
|
63
|
+
theme?: BundledTheme | 'light' | 'dark'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Highlight code using Shiki
|
|
68
|
+
*
|
|
69
|
+
* @param code - The code to highlight
|
|
70
|
+
* @param options - Highlighting options
|
|
71
|
+
* @returns The highlighted code as HTML
|
|
72
|
+
*/
|
|
73
|
+
function resolveTheme(themeOption: string | undefined): BundledTheme {
|
|
74
|
+
if (themeOption === 'light') return 'github-light'
|
|
75
|
+
if (themeOption === 'dark' || !themeOption) return 'github-dark'
|
|
76
|
+
return themeOption as BundledTheme
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function isValidCode(code: unknown): code is string {
|
|
80
|
+
return Boolean(code) && typeof code === 'string'
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function highlightCode(code: string, options: HighlightOptions = {}): Promise<string> {
|
|
84
|
+
if (!isValidCode(code)) throw new Error('Invalid code provided for highlighting')
|
|
85
|
+
|
|
86
|
+
const hl = await initializeHighlighter()
|
|
87
|
+
const lang = (options.lang ?? 'text') as BundledLanguage
|
|
88
|
+
const theme = resolveTheme(options.theme)
|
|
89
|
+
const loadedLangs = hl.getLoadedLanguages()
|
|
90
|
+
const effectiveLang = loadedLangs.includes(lang) ? lang : 'text'
|
|
91
|
+
|
|
92
|
+
return hl
|
|
93
|
+
.codeToHtml(code, { lang: effectiveLang, theme })
|
|
94
|
+
.replace(/(<pre[^>]+) style="[^"]*"/, '$1')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Preload the syntax highlighter for faster initial rendering
|
|
99
|
+
* Errors are silently ignored since preloading is optional
|
|
100
|
+
*/
|
|
101
|
+
export async function preloadHighlighter(): Promise<void> {
|
|
102
|
+
try {
|
|
103
|
+
await initializeHighlighter()
|
|
104
|
+
} catch {
|
|
105
|
+
// Preload failures are non-critical - highlighting will still work on demand
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get list of supported languages
|
|
111
|
+
*/
|
|
112
|
+
export function getSupportedLanguages(): readonly string[] {
|
|
113
|
+
return SUPPORTED_LANGUAGES
|
|
114
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upload utility functions — shared helpers for UploadTarget and UploadProgress.
|
|
3
|
+
* Pure functions with no Svelte dependency.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const ARCHIVE_TYPES = new Set(['application/zip', 'application/gzip', 'application/x-tar'])
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if a file matches an accept string (comma-separated MIME types and extensions).
|
|
10
|
+
* @param {{ type: string, name: string }} file
|
|
11
|
+
* @param {string | null | undefined} accept - e.g. 'image/*,.pdf,application/json'
|
|
12
|
+
* @returns {boolean}
|
|
13
|
+
*/
|
|
14
|
+
export function matchesAccept(file, accept) {
|
|
15
|
+
if (!accept) return true
|
|
16
|
+
|
|
17
|
+
const tokens = accept
|
|
18
|
+
.split(',')
|
|
19
|
+
.map((t) => t.trim())
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
if (tokens.length === 0) return true
|
|
22
|
+
|
|
23
|
+
return tokens.some((token) => {
|
|
24
|
+
if (token.startsWith('.')) {
|
|
25
|
+
// Extension match (case-insensitive)
|
|
26
|
+
return file.name.toLowerCase().endsWith(token.toLowerCase())
|
|
27
|
+
}
|
|
28
|
+
if (token.endsWith('/*')) {
|
|
29
|
+
// Wildcard MIME type match (e.g. image/*)
|
|
30
|
+
const prefix = token.slice(0, -1) // 'image/'
|
|
31
|
+
return file.type.startsWith(prefix)
|
|
32
|
+
}
|
|
33
|
+
// Exact MIME type match
|
|
34
|
+
return file.type === token
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Validate a file against accept and maxSize constraints.
|
|
40
|
+
* @param {{ type: string, name: string, size: number }} file
|
|
41
|
+
* @param {{ accept?: string, maxSize?: number }} constraints
|
|
42
|
+
* @returns {true | { reason: 'type' | 'size' }}
|
|
43
|
+
*/
|
|
44
|
+
function hasTypeError(file, accept) {
|
|
45
|
+
return accept && !matchesAccept(file, accept)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function hasSizeError(file, maxSize) {
|
|
49
|
+
return maxSize !== undefined && file.size > maxSize
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function validateFile(file, { accept, maxSize } = {}) {
|
|
53
|
+
if (hasTypeError(file, accept)) return { reason: 'type' }
|
|
54
|
+
if (hasSizeError(file, maxSize)) return { reason: 'size' }
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Map a MIME type to an icon class string.
|
|
60
|
+
* @param {string | null | undefined} mimeType
|
|
61
|
+
* @returns {string}
|
|
62
|
+
*/
|
|
63
|
+
const MIME_PREFIX_ICONS = [
|
|
64
|
+
['image/', 'i-lucide:image'],
|
|
65
|
+
['video/', 'i-lucide:video'],
|
|
66
|
+
['audio/', 'i-lucide:music'],
|
|
67
|
+
['text/', 'i-lucide:file-text'],
|
|
68
|
+
['application/pdf', 'i-lucide:file-text']
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
function getPrefixIcon(mimeType) {
|
|
72
|
+
for (const [prefix, icon] of MIME_PREFIX_ICONS) {
|
|
73
|
+
if (mimeType.startsWith(prefix)) return icon
|
|
74
|
+
}
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function inferIcon(mimeType) {
|
|
79
|
+
if (!mimeType) return 'i-lucide:file'
|
|
80
|
+
const prefixIcon = getPrefixIcon(mimeType)
|
|
81
|
+
if (prefixIcon) return prefixIcon
|
|
82
|
+
if (ARCHIVE_TYPES.has(mimeType)) return 'i-lucide:archive'
|
|
83
|
+
return 'i-lucide:file'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Format a byte count as a human-readable size string.
|
|
88
|
+
* @param {number} bytes
|
|
89
|
+
* @returns {string}
|
|
90
|
+
*/
|
|
91
|
+
export function formatSize(bytes) {
|
|
92
|
+
if (bytes < 1024) return `${bytes} B`
|
|
93
|
+
if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB`
|
|
94
|
+
if (bytes < 1024 ** 3) return `${(bytes / 1024 ** 2).toFixed(1)} MB`
|
|
95
|
+
return `${(bytes / 1024 ** 3).toFixed(1)} GB`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Group a flat file array by path field into a nested tree structure.
|
|
100
|
+
* Root-level items (empty path) stay ungrouped.
|
|
101
|
+
* Group nodes use `text` as the label field (ProxyItem compatibility).
|
|
102
|
+
*
|
|
103
|
+
* @param {Array<Record<string, any>>} items
|
|
104
|
+
* @param {string} pathField - field name containing the path (e.g. 'path')
|
|
105
|
+
* @param {string} childrenField - field name for children arrays (e.g. 'children')
|
|
106
|
+
* @returns {Array<Record<string, any>>}
|
|
107
|
+
*/
|
|
108
|
+
function resolveFolder(ctx, parent, segment, fullPath) {
|
|
109
|
+
let folder = ctx.folderMap.get(fullPath)
|
|
110
|
+
if (!folder) {
|
|
111
|
+
folder = { text: segment, [ctx.childrenField]: [] }
|
|
112
|
+
ctx.folderMap.set(fullPath, folder)
|
|
113
|
+
parent.push(folder)
|
|
114
|
+
}
|
|
115
|
+
return folder[ctx.childrenField]
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function walkSegments(ctx, item, rawPath, root) {
|
|
119
|
+
const segments = rawPath.split('/').filter(Boolean)
|
|
120
|
+
let parent = root
|
|
121
|
+
let fullPath = ''
|
|
122
|
+
for (const segment of segments) {
|
|
123
|
+
fullPath = fullPath ? `${fullPath}/${segment}` : segment
|
|
124
|
+
parent = resolveFolder(ctx, parent, segment, fullPath)
|
|
125
|
+
}
|
|
126
|
+
parent.push(item)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function groupByPath(items, pathField, childrenField) {
|
|
130
|
+
if (!items?.length) return []
|
|
131
|
+
|
|
132
|
+
const root = []
|
|
133
|
+
const ctx = { folderMap: new Map(), childrenField }
|
|
134
|
+
|
|
135
|
+
for (const item of items) {
|
|
136
|
+
const rawPath = item[pathField]
|
|
137
|
+
if (!rawPath) {
|
|
138
|
+
root.push(item)
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
walkSegments(ctx, item, rawPath, root)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return root
|
|
145
|
+
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022 Jerry Thomas
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/src/index.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// skipcq: JS-E1004 - Needed for exposing all components
|
|
2
|
-
export * from '@rokkit/atoms'
|
|
3
|
-
// skipcq: JS-E1004 - Needed for exposing all components
|
|
4
|
-
export * from '@rokkit/molecules'
|
|
5
|
-
// skipcq: JS-E1004 - Needed for exposing all components
|
|
6
|
-
export * from '@rokkit/organisms'
|
|
7
|
-
// skipcq: JS-E1004 - Needed for exposing all components
|
|
8
|
-
export * from '@rokkit/layout'
|
package/src/wrappers.js
DELETED