svelte-multiselect 11.5.2 → 11.6.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/CmdPalette.svelte.d.ts +2 -2
- package/dist/MultiSelect.svelte +207 -94
- package/dist/MultiSelect.svelte.d.ts +2 -2
- package/dist/Nav.svelte +108 -55
- package/dist/Nav.svelte.d.ts +1 -1
- package/dist/attachments.d.ts +2 -0
- package/dist/attachments.js +4 -1
- package/dist/heading-anchors.js +10 -16
- package/dist/live-examples/highlighter.js +62 -0
- package/dist/live-examples/index.d.ts +7 -0
- package/dist/live-examples/index.js +23 -0
- package/dist/live-examples/mdsvex-transform.d.ts +32 -0
- package/dist/live-examples/mdsvex-transform.js +184 -0
- package/dist/live-examples/vite-plugin.d.ts +6 -0
- package/dist/live-examples/vite-plugin.js +170 -0
- package/dist/types.d.ts +15 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +11 -0
- package/package.json +37 -14
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// Remark plugin - transforms ```svelte example code blocks into rendered components
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { hast_to_html, LANG_TO_SCOPE, starry_night } from './highlighter.js';
|
|
5
|
+
// Base64 encode to prevent preprocessors from modifying the content
|
|
6
|
+
const to_base64 = (src) => Buffer.from(src, `utf-8`).toString(`base64`);
|
|
7
|
+
// Escape backticks and template literal syntax for embedding in template literals
|
|
8
|
+
const encode_escapes = (src) => src.replace(/`/g, `\\\``).replace(/\$\{/g, `\\$\{`);
|
|
9
|
+
// Regex to find <script> block in svelte
|
|
10
|
+
// Note: These patterns handle common cases but may have edge cases with nested
|
|
11
|
+
// comments containing </script> strings or complex attribute syntax
|
|
12
|
+
const RE_SCRIPT_START = /<script(?:\s+?[a-zA-Z]+(=(?:["']){0,1}[a-zA-Z0-9]+(?:["']){0,1}){0,1})*\s*?>/;
|
|
13
|
+
const RE_SCRIPT_BLOCK = /(<script[\s\S]*?>)([\s\S]*?)(<\/script>)/g;
|
|
14
|
+
const RE_STYLE_BLOCK = /(<style[\s\S]*?>)([\s\S]*?)(<\/style>)/g;
|
|
15
|
+
// Parses key=value pairs from a string. Supports strings (with escaped quotes),
|
|
16
|
+
// numbers, booleans, and arrays. Note: nested structures in arrays are not supported.
|
|
17
|
+
const RE_PARSE_META = /(\w+=\d+|\w+="(?:[^"\\]|\\.)*"|\w+=\[[^\]]*\]|\w+)/g;
|
|
18
|
+
export const EXAMPLE_MODULE_PREFIX = `___live_example___`;
|
|
19
|
+
export const EXAMPLE_COMPONENT_PREFIX = `LiveExample___`;
|
|
20
|
+
// Languages that render as live Svelte components (O(1) lookup)
|
|
21
|
+
const LIVE_LANGUAGES = new Set([`svelte`, `html`]);
|
|
22
|
+
// All languages that support the `example` meta (O(1) lookup)
|
|
23
|
+
const EXAMPLE_LANGUAGES = new Set(Object.keys(LANG_TO_SCOPE));
|
|
24
|
+
// Simple tree traversal - finds all nodes of a given type
|
|
25
|
+
const visit = (tree, type, callback) => {
|
|
26
|
+
const walk = (nodes) => {
|
|
27
|
+
for (const node of nodes) {
|
|
28
|
+
if (node.type === type)
|
|
29
|
+
callback(node);
|
|
30
|
+
if (node.children)
|
|
31
|
+
walk(node.children);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
walk(tree.children);
|
|
35
|
+
};
|
|
36
|
+
// Default wrapper component
|
|
37
|
+
const DEFAULT_WRAPPER = `$lib/CodeExample.svelte`;
|
|
38
|
+
function remark(options = {}) {
|
|
39
|
+
const { defaults = {} } = options;
|
|
40
|
+
return function transformer(tree, file) {
|
|
41
|
+
const examples = [];
|
|
42
|
+
// Track wrapper imports to avoid duplicates and generate unique aliases
|
|
43
|
+
const wrapper_aliases = new Map(); // wrapper key -> alias name
|
|
44
|
+
const filename = path.relative(file.cwd, file.filename);
|
|
45
|
+
// Helper to get or create a wrapper alias
|
|
46
|
+
function get_wrapper_alias(wrapper) {
|
|
47
|
+
// Use '::' as delimiter to avoid misparsing paths with colons (Windows, URLs)
|
|
48
|
+
const wrapper_key = typeof wrapper === `string`
|
|
49
|
+
? wrapper
|
|
50
|
+
: `${wrapper[0]}::${wrapper[1]}`;
|
|
51
|
+
let alias = wrapper_aliases.get(wrapper_key);
|
|
52
|
+
if (!alias) {
|
|
53
|
+
alias = `Example_${wrapper_aliases.size}`;
|
|
54
|
+
wrapper_aliases.set(wrapper_key, alias);
|
|
55
|
+
}
|
|
56
|
+
return alias;
|
|
57
|
+
}
|
|
58
|
+
visit(tree, `code`, (node) => {
|
|
59
|
+
const meta = {
|
|
60
|
+
Wrapper: DEFAULT_WRAPPER,
|
|
61
|
+
filename,
|
|
62
|
+
...defaults,
|
|
63
|
+
...parse_meta(node.meta || ``),
|
|
64
|
+
};
|
|
65
|
+
const { csr, example, Wrapper } = meta;
|
|
66
|
+
// find code blocks with `example` meta in supported languages
|
|
67
|
+
if (example && node.lang && EXAMPLE_LANGUAGES.has(node.lang)) {
|
|
68
|
+
const is_live = LIVE_LANGUAGES.has(node.lang);
|
|
69
|
+
const wrapper_alias = is_live ? get_wrapper_alias(Wrapper ?? DEFAULT_WRAPPER) : ``;
|
|
70
|
+
const value = create_example_component(node.value || ``, meta, is_live ? examples.length : -1, // -1 for code-only (no component import needed)
|
|
71
|
+
node.lang, is_live, wrapper_alias);
|
|
72
|
+
// Only track live examples for component imports
|
|
73
|
+
if (is_live) {
|
|
74
|
+
examples.push({ csr, wrapper_alias });
|
|
75
|
+
}
|
|
76
|
+
node.type = `paragraph`;
|
|
77
|
+
node.children = [{ type: `text`, value }];
|
|
78
|
+
delete node.lang;
|
|
79
|
+
delete node.meta;
|
|
80
|
+
delete node.value;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
// add imports for each generated example
|
|
84
|
+
let scripts = ``;
|
|
85
|
+
// Add wrapper imports
|
|
86
|
+
// Use '::' as the tuple delimiter to avoid misparsing Windows paths (C:\path)
|
|
87
|
+
// or URLs (https://example.com) that contain single colons
|
|
88
|
+
for (const [wrapper_key, alias] of wrapper_aliases) {
|
|
89
|
+
const double_colon_idx = wrapper_key.indexOf(`::`);
|
|
90
|
+
if (double_colon_idx === -1) {
|
|
91
|
+
// Simple string path (default import)
|
|
92
|
+
scripts += `import ${alias} from "${wrapper_key}";\n`;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Tuple [module, export] using '::' delimiter
|
|
96
|
+
const module_path = wrapper_key.slice(0, double_colon_idx);
|
|
97
|
+
const export_name = wrapper_key.slice(double_colon_idx + 2);
|
|
98
|
+
scripts += `import { ${export_name} as ${alias} } from "${module_path}";\n`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Add example component imports
|
|
102
|
+
for (const [idx, ex] of examples.entries()) {
|
|
103
|
+
if (!ex.csr) {
|
|
104
|
+
scripts +=
|
|
105
|
+
`import ${EXAMPLE_COMPONENT_PREFIX}${idx} from "${EXAMPLE_MODULE_PREFIX}${idx}.svelte";\n`;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Try to inject imports into existing script block
|
|
109
|
+
let injected = false;
|
|
110
|
+
visit(tree, `html`, (node) => {
|
|
111
|
+
if (!injected && node.value && RE_SCRIPT_START.test(node.value)) {
|
|
112
|
+
node.value = node.value.replace(RE_SCRIPT_START, (opening_tag) => `${opening_tag}\n${scripts}`);
|
|
113
|
+
injected = true;
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
// Create script block if none existed
|
|
117
|
+
if (!injected) {
|
|
118
|
+
tree.children.push({ type: `html`, value: `<script>\n${scripts}</script>` });
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function parse_meta(meta) {
|
|
123
|
+
const result = {};
|
|
124
|
+
for (const part of meta.match(RE_PARSE_META) ?? []) {
|
|
125
|
+
const eq = part.indexOf(`=`);
|
|
126
|
+
const key = eq === -1 ? part : part.slice(0, eq);
|
|
127
|
+
const value = eq === -1 ? `true` : part.slice(eq + 1);
|
|
128
|
+
try {
|
|
129
|
+
result[key] = JSON.parse(value);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
throw new Error(`Unable to parse meta \`${key}=${value}\``);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
function format_code(code, meta) {
|
|
138
|
+
let result = code;
|
|
139
|
+
if (meta.hideScript)
|
|
140
|
+
result = result.replace(RE_SCRIPT_BLOCK, ``);
|
|
141
|
+
if (meta.hideStyle)
|
|
142
|
+
result = result.replace(RE_STYLE_BLOCK, ``);
|
|
143
|
+
return result.trim();
|
|
144
|
+
}
|
|
145
|
+
function create_example_component(value, meta, index, lang, is_live, wrapper_alias) {
|
|
146
|
+
const code = format_code(value, meta);
|
|
147
|
+
const tree = starry_night.highlight(code, LANG_TO_SCOPE[lang]);
|
|
148
|
+
// Convert newlines to to prevent bundlers from stripping whitespace
|
|
149
|
+
const highlighted = hast_to_html(tree).replace(/\n/g, ` `);
|
|
150
|
+
// Code-only examples (ts, js, css, etc.) - just render highlighted code block
|
|
151
|
+
if (!is_live) {
|
|
152
|
+
// Close and reopen <p> to avoid block-in-inline HTML nesting issues
|
|
153
|
+
return `</p><pre class="highlight highlight-${lang}"><code>{@html ${JSON.stringify(highlighted)}}</code></pre><p>`;
|
|
154
|
+
}
|
|
155
|
+
// Live examples (svelte, html) - render with CodeExample wrapper
|
|
156
|
+
const component = `${EXAMPLE_COMPONENT_PREFIX}${index}`;
|
|
157
|
+
const base64_src = to_base64(value);
|
|
158
|
+
const escaped_src = JSON.stringify(encode_escapes(code));
|
|
159
|
+
const escaped_meta = encode_escapes(JSON.stringify(meta));
|
|
160
|
+
// Close and reopen <p> to avoid block-in-inline HTML nesting issues
|
|
161
|
+
return `</p>
|
|
162
|
+
<${wrapper_alias}
|
|
163
|
+
__live_example_src={"${base64_src}"}
|
|
164
|
+
src={${escaped_src}}
|
|
165
|
+
meta={${escaped_meta}}
|
|
166
|
+
>
|
|
167
|
+
{#snippet example()}
|
|
168
|
+
${meta.csr
|
|
169
|
+
? `{#if typeof window !== 'undefined'}
|
|
170
|
+
{#await import("${EXAMPLE_MODULE_PREFIX}${index}.svelte") then module}
|
|
171
|
+
{@const ${component} = module.default}
|
|
172
|
+
<${component} />
|
|
173
|
+
{/await}
|
|
174
|
+
{/if}`
|
|
175
|
+
: `<${component} />`}
|
|
176
|
+
{/snippet}
|
|
177
|
+
|
|
178
|
+
{#snippet code()}
|
|
179
|
+
{@html ${JSON.stringify(highlighted)}}
|
|
180
|
+
{/snippet}
|
|
181
|
+
</${wrapper_alias}>
|
|
182
|
+
<p>`;
|
|
183
|
+
}
|
|
184
|
+
export default remark;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Vite plugin - handles virtual module resolution for example components
|
|
2
|
+
// @ts-expect-error no types available
|
|
3
|
+
import ast from 'abstract-syntax-tree';
|
|
4
|
+
import { Buffer } from 'node:buffer';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import { EXAMPLE_MODULE_PREFIX } from './mdsvex-transform.js';
|
|
8
|
+
export { EXAMPLE_MODULE_PREFIX };
|
|
9
|
+
// Max chars to scan after property end for trailing comma/whitespace cleanup
|
|
10
|
+
const TRAILING_CLEANUP_BOUND = 50; // Generous bound - typical trailing content is ", " (2 chars)
|
|
11
|
+
// Apply edits in reverse order so positions stay valid
|
|
12
|
+
const apply_edits = (source, edits) => edits
|
|
13
|
+
.sort((a, b) => b.start - a.start)
|
|
14
|
+
.reduce((str, { start, end, content }) => str.slice(0, start) + content + str.slice(end), source);
|
|
15
|
+
export default function live_examples_plugin(options = {}) {
|
|
16
|
+
const { extensions = [`.svelte.md`, `.md`, `.svx`] } = options;
|
|
17
|
+
// Extracted examples as individual virtual files (id -> svelte source)
|
|
18
|
+
const virtual_files = new Map();
|
|
19
|
+
// Reverse lookup: parent markdown path -> set of virtual file IDs (for O(1) HMR lookups)
|
|
20
|
+
const parent_to_virtual = new Map();
|
|
21
|
+
let vite_server;
|
|
22
|
+
return {
|
|
23
|
+
name: `live-examples-plugin`,
|
|
24
|
+
configureServer(server) {
|
|
25
|
+
vite_server = server;
|
|
26
|
+
},
|
|
27
|
+
resolveId(id) {
|
|
28
|
+
if (id.includes(EXAMPLE_MODULE_PREFIX)) {
|
|
29
|
+
// Force absolute path (dev uses relative, prod uses absolute)
|
|
30
|
+
// Use posix.join to ensure forward slashes on all platforms (Vite normalizes to /)
|
|
31
|
+
const cwd = process.cwd().replace(/\\/g, `/`);
|
|
32
|
+
return id.includes(cwd) ? id : path.posix.join(cwd, id);
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
load(id) {
|
|
36
|
+
if (id.includes(EXAMPLE_MODULE_PREFIX)) {
|
|
37
|
+
// Strip query parameters - Vite requests derived modules (styles, etc.) with queries
|
|
38
|
+
// like ?inline&svelte&type=style&lang.css but we store the base path
|
|
39
|
+
const [base_id, query = ``] = id.split(`?`);
|
|
40
|
+
const src = virtual_files.get(base_id);
|
|
41
|
+
if (src)
|
|
42
|
+
return src;
|
|
43
|
+
// Virtual file not found - can happen during SSR/parallel builds when derived
|
|
44
|
+
// modules (styles, scripts) are requested before parent markdown is transformed.
|
|
45
|
+
// For derived module requests, return empty content to avoid crashes.
|
|
46
|
+
if (query.includes(`type=style`) || query.includes(`type=script`) ||
|
|
47
|
+
query.includes(`type=module`)) {
|
|
48
|
+
return ``;
|
|
49
|
+
}
|
|
50
|
+
// For main component requests in production, fail the build
|
|
51
|
+
const msg = `Example src not found for ${id}`;
|
|
52
|
+
if (process.env.NODE_ENV === `production`) {
|
|
53
|
+
throw new Error(msg);
|
|
54
|
+
}
|
|
55
|
+
// In dev, warn and return error component to surface issue visibly
|
|
56
|
+
this.warn(msg);
|
|
57
|
+
return `<script>console.error(${JSON.stringify(msg)})</script><p style="color:red">${msg}</p>`;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
transform(code, id) {
|
|
61
|
+
// Strip query params for extension check (Vite adds ?query for HMR, styles, etc.)
|
|
62
|
+
const base_id = id.split(`?`)[0];
|
|
63
|
+
// Skip non-matching files
|
|
64
|
+
const is_example_module = id.includes(EXAMPLE_MODULE_PREFIX);
|
|
65
|
+
const is_markdown = extensions.some((ext) => base_id.endsWith(ext));
|
|
66
|
+
if (!is_example_module && !is_markdown)
|
|
67
|
+
return;
|
|
68
|
+
// Skip derived modules (styles, etc.) - only process the main markdown file
|
|
69
|
+
// Vite creates derived modules like ?svelte&type=style&lang.css for style blocks
|
|
70
|
+
if (id.includes(`?svelte&type=`))
|
|
71
|
+
return { code, map: { mappings: `` } };
|
|
72
|
+
if (is_markdown) {
|
|
73
|
+
// Use AST for precise node location, collect edits to apply at end
|
|
74
|
+
let tree;
|
|
75
|
+
try {
|
|
76
|
+
tree = ast.parse(code, { ranges: true });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Code may contain Svelte syntax that the JS parser can't handle
|
|
80
|
+
// (e.g., template blocks, special directives). Skip transformation.
|
|
81
|
+
return { code, map: { mappings: `` } };
|
|
82
|
+
}
|
|
83
|
+
const edits = [];
|
|
84
|
+
// Find all __live_example_src properties
|
|
85
|
+
const src_props = ast.find(tree, {
|
|
86
|
+
type: `Property`,
|
|
87
|
+
key: { name: `__live_example_src` },
|
|
88
|
+
});
|
|
89
|
+
for (const [idx, prop] of src_props.entries()) {
|
|
90
|
+
// Extract the string literal content (base64 encoded)
|
|
91
|
+
const string_literals = ast.find(prop, {
|
|
92
|
+
type: `Literal`,
|
|
93
|
+
});
|
|
94
|
+
if (string_literals.length === 0)
|
|
95
|
+
continue;
|
|
96
|
+
const value_node = string_literals[0];
|
|
97
|
+
// AST Literal nodes store value in .value property (string for literals)
|
|
98
|
+
const src = Buffer.from(String(value_node.value ?? ``), `base64`).toString(`utf-8`);
|
|
99
|
+
// Use base_id (without query params) to ensure consistent virtual file IDs
|
|
100
|
+
const virtual_id = `${base_id}${EXAMPLE_MODULE_PREFIX}${idx}.svelte`;
|
|
101
|
+
if (src !== virtual_files.get(virtual_id)) {
|
|
102
|
+
virtual_files.set(virtual_id, src);
|
|
103
|
+
// Update reverse lookup for HMR (get-or-create pattern)
|
|
104
|
+
const virtual_set = parent_to_virtual.get(base_id) ?? new Set();
|
|
105
|
+
if (!parent_to_virtual.has(base_id)) {
|
|
106
|
+
parent_to_virtual.set(base_id, virtual_set);
|
|
107
|
+
}
|
|
108
|
+
virtual_set.add(virtual_id);
|
|
109
|
+
// Invalidate modules for HMR
|
|
110
|
+
if (vite_server) {
|
|
111
|
+
const mod = vite_server.moduleGraph.getModuleById(virtual_id);
|
|
112
|
+
const parent_mod = vite_server.moduleGraph.getModuleById(base_id);
|
|
113
|
+
if (mod)
|
|
114
|
+
vite_server.moduleGraph.invalidateModule(mod);
|
|
115
|
+
if (parent_mod)
|
|
116
|
+
vite_server.moduleGraph.invalidateModule(parent_mod);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Remove the property (including trailing comma/whitespace)
|
|
120
|
+
if (prop.start !== undefined && prop.end !== undefined) {
|
|
121
|
+
let end = prop.end;
|
|
122
|
+
const max_end = Math.min(prop.end + TRAILING_CLEANUP_BOUND, code.length);
|
|
123
|
+
while (end < max_end && /[\s,]/.test(code[end]))
|
|
124
|
+
end++;
|
|
125
|
+
edits.push({ start: prop.start, end, content: `` });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Update import paths (static and dynamic) to use virtual file IDs
|
|
129
|
+
const imports = [
|
|
130
|
+
...ast.find(tree, { type: `ImportDeclaration` }),
|
|
131
|
+
...ast.find(tree, { type: `ImportExpression` }),
|
|
132
|
+
];
|
|
133
|
+
for (const { source } of imports) {
|
|
134
|
+
const match = source?.value?.match(/___live_example___(\d+)\.svelte/);
|
|
135
|
+
if (match && source?.start !== undefined && source?.end !== undefined) {
|
|
136
|
+
const virtual_id = `${base_id}${EXAMPLE_MODULE_PREFIX}${match[1]}.svelte`;
|
|
137
|
+
edits.push({
|
|
138
|
+
start: source.start + 1,
|
|
139
|
+
end: source.end - 1,
|
|
140
|
+
content: virtual_id,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
code: apply_edits(code, edits),
|
|
146
|
+
map: { mappings: `` },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return { code, map: { mappings: `` } };
|
|
150
|
+
},
|
|
151
|
+
handleHotUpdate(ctx) {
|
|
152
|
+
// Collect virtual file modules that need HMR updates
|
|
153
|
+
const additional_modules = [];
|
|
154
|
+
// Normalize to forward slashes (ctx.file uses OS separators, Map keys use Vite's forward slashes)
|
|
155
|
+
const file = ctx.file.replace(/\\/g, `/`);
|
|
156
|
+
// O(1) lookup using reverse map instead of iterating all virtual files
|
|
157
|
+
if (extensions.some((ext) => file.endsWith(ext))) {
|
|
158
|
+
const virtual_ids = parent_to_virtual.get(file);
|
|
159
|
+
if (virtual_ids) {
|
|
160
|
+
for (const id of virtual_ids) {
|
|
161
|
+
const mod = ctx.server.moduleGraph.getModuleById(id);
|
|
162
|
+
if (mod)
|
|
163
|
+
additional_modules.push(mod);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return [...additional_modules, ...ctx.modules];
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -78,6 +78,14 @@ export interface MultiSelectEvents<T extends Option = Option> {
|
|
|
78
78
|
option: T | null;
|
|
79
79
|
index: number | null;
|
|
80
80
|
}) => unknown;
|
|
81
|
+
onundo?: (data: {
|
|
82
|
+
previous: T[];
|
|
83
|
+
current: T[];
|
|
84
|
+
}) => unknown;
|
|
85
|
+
onredo?: (data: {
|
|
86
|
+
previous: T[];
|
|
87
|
+
current: T[];
|
|
88
|
+
}) => unknown;
|
|
81
89
|
}
|
|
82
90
|
export interface LoadOptionsParams {
|
|
83
91
|
search: string;
|
|
@@ -222,12 +230,19 @@ export interface MultiSelectProps<T extends Option = Option> extends MultiSelect
|
|
|
222
230
|
collapseAllGroups?: () => void;
|
|
223
231
|
expandAllGroups?: () => void;
|
|
224
232
|
shortcuts?: Partial<KeyboardShortcuts>;
|
|
233
|
+
history?: boolean | number;
|
|
234
|
+
undo?: () => boolean;
|
|
235
|
+
redo?: () => boolean;
|
|
236
|
+
canUndo?: boolean;
|
|
237
|
+
canRedo?: boolean;
|
|
225
238
|
}
|
|
226
239
|
export interface KeyboardShortcuts {
|
|
227
240
|
select_all?: string | null;
|
|
228
241
|
clear_all?: string | null;
|
|
229
242
|
open?: string | null;
|
|
230
243
|
close?: string | null;
|
|
244
|
+
undo?: string | null;
|
|
245
|
+
redo?: string | null;
|
|
231
246
|
}
|
|
232
247
|
export interface NavRouteObject {
|
|
233
248
|
href: string;
|
package/dist/utils.d.ts
CHANGED
package/dist/utils.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
let uuid_counter = 0;
|
|
2
|
+
// Generates a UUID for component IDs. Uses native crypto.randomUUID when available.
|
|
3
|
+
// Fallback uses timestamp+counter - sufficient for DOM IDs (uniqueness, not security).
|
|
4
|
+
// Cryptographic randomness is unnecessary here since these IDs are only used for
|
|
5
|
+
// associating labels with inputs and ensuring unique DOM element identifiers.
|
|
6
|
+
export function get_uuid() {
|
|
7
|
+
if (globalThis.crypto?.randomUUID)
|
|
8
|
+
return globalThis.crypto.randomUUID();
|
|
9
|
+
const hex = (Date.now().toString(16) + (uuid_counter++).toString(16)).padStart(32, `0`);
|
|
10
|
+
return hex.replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, `$1-$2-$3-$4-$5`);
|
|
11
|
+
}
|
|
1
12
|
// Type guard for checking if a value is a non-null object
|
|
2
13
|
export const is_object = (val) => typeof val === `object` && val !== null;
|
|
3
14
|
// Type guard for checking if an option has a group key
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"homepage": "https://janosh.github.io/svelte-multiselect",
|
|
6
6
|
"repository": "https://github.com/janosh/svelte-multiselect",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"version": "11.
|
|
8
|
+
"version": "11.6.0",
|
|
9
9
|
"type": "module",
|
|
10
10
|
"scripts": {
|
|
11
11
|
"dev": "vite dev",
|
|
@@ -13,37 +13,52 @@
|
|
|
13
13
|
"preview": "vite preview",
|
|
14
14
|
"test": "vitest --run && playwright test",
|
|
15
15
|
"check": "svelte-check",
|
|
16
|
-
"package": "svelte-package",
|
|
17
|
-
"prepublishOnly": "
|
|
16
|
+
"package": "svelte-package && find dist -name '*.js' -o -name '*.d.ts' | xargs sed -i '' -E \"s/(\\.\\.?\\/[^'\\\"]*)\\.ts(['\\\"])/\\1.js\\2/g\"",
|
|
17
|
+
"prepublishOnly": "pnpm package"
|
|
18
18
|
},
|
|
19
19
|
"svelte": "./dist/index.js",
|
|
20
20
|
"bugs": "https://github.com/janosh/svelte-multiselect/issues",
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"
|
|
22
|
+
"@wooorm/starry-night": "^3.0.0",
|
|
23
|
+
"abstract-syntax-tree": "^2.0.0",
|
|
24
|
+
"svelte": "^5.48.0",
|
|
25
|
+
"svelte-preprocess": "^6.0.0"
|
|
26
|
+
},
|
|
27
|
+
"peerDependenciesMeta": {
|
|
28
|
+
"@wooorm/starry-night": {
|
|
29
|
+
"optional": true
|
|
30
|
+
},
|
|
31
|
+
"abstract-syntax-tree": {
|
|
32
|
+
"optional": true
|
|
33
|
+
},
|
|
34
|
+
"svelte-preprocess": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
23
37
|
},
|
|
24
38
|
"devDependencies": {
|
|
25
|
-
"@playwright/test": "^1.
|
|
26
|
-
"@stylistic/eslint-plugin": "^5.7.
|
|
39
|
+
"@playwright/test": "^1.58.0",
|
|
40
|
+
"@stylistic/eslint-plugin": "^5.7.1",
|
|
27
41
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
28
|
-
"@sveltejs/kit": "^2.50.
|
|
42
|
+
"@sveltejs/kit": "^2.50.1",
|
|
29
43
|
"@sveltejs/package": "2.5.7",
|
|
30
44
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
31
|
-
"@types/node": "^25.0.
|
|
32
|
-
"@vitest/coverage-v8": "^4.0.
|
|
45
|
+
"@types/node": "^25.0.10",
|
|
46
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
47
|
+
"@wooorm/starry-night": "^3.9.0",
|
|
48
|
+
"abstract-syntax-tree": "^2.22.0",
|
|
33
49
|
"eslint": "^9.39.2",
|
|
34
50
|
"eslint-plugin-svelte": "^3.14.0",
|
|
35
|
-
"happy-dom": "^20.3.
|
|
51
|
+
"happy-dom": "^20.3.7",
|
|
36
52
|
"mdsvex": "^0.12.6",
|
|
37
|
-
"
|
|
38
|
-
"svelte": "^5.46.4",
|
|
53
|
+
"svelte": "^5.48.2",
|
|
39
54
|
"svelte-check": "^4.3.5",
|
|
40
55
|
"svelte-preprocess": "^6.0.3",
|
|
41
56
|
"svelte-toc": "^0.6.2",
|
|
42
57
|
"svelte2tsx": "^0.7.46",
|
|
43
58
|
"typescript": "5.9.3",
|
|
44
|
-
"typescript-eslint": "^8.53.
|
|
59
|
+
"typescript-eslint": "^8.53.1",
|
|
45
60
|
"vite": "^7.3.1",
|
|
46
|
-
"vitest": "^4.0.
|
|
61
|
+
"vitest": "^4.0.18"
|
|
47
62
|
},
|
|
48
63
|
"keywords": [
|
|
49
64
|
"svelte",
|
|
@@ -70,9 +85,17 @@
|
|
|
70
85
|
"types": "./dist/attachments.d.ts",
|
|
71
86
|
"default": "./dist/attachments.js"
|
|
72
87
|
},
|
|
88
|
+
"./utils": {
|
|
89
|
+
"types": "./dist/utils.d.ts",
|
|
90
|
+
"default": "./dist/utils.js"
|
|
91
|
+
},
|
|
73
92
|
"./heading-anchors": {
|
|
74
93
|
"types": "./dist/heading-anchors.d.ts",
|
|
75
94
|
"default": "./dist/heading-anchors.js"
|
|
95
|
+
},
|
|
96
|
+
"./live-examples": {
|
|
97
|
+
"types": "./dist/live-examples/index.d.ts",
|
|
98
|
+
"default": "./dist/live-examples/index.js"
|
|
76
99
|
}
|
|
77
100
|
},
|
|
78
101
|
"types": "./dist/index.d.ts",
|