@liwe3/webcomponents-svelte 1.0.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/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # @liwe3/webcomponents-svelte
2
+
3
+ Svelte 5 wrappers for [@liwe3/webcomponents](https://www.npmjs.com/package/@liwe3/webcomponents).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @liwe3/webcomponents @liwe3/webcomponents-svelte
9
+ # or
10
+ pnpm add @liwe3/webcomponents @liwe3/webcomponents-svelte
11
+ # or
12
+ yarn add @liwe3/webcomponents @liwe3/webcomponents-svelte
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ### SmartSelect
18
+
19
+ ```svelte
20
+ <script>
21
+ import { SmartSelect } from '@liwe3/webcomponents-svelte';
22
+
23
+ let selectedValue = $state();
24
+
25
+ const options = [
26
+ { value: 'js', label: 'JavaScript' },
27
+ { value: 'ts', label: 'TypeScript' },
28
+ { value: 'py', label: 'Python' }
29
+ ];
30
+
31
+ const handleChange = (newValue) => {
32
+ console.log('Selected:', newValue);
33
+ };
34
+ </script>
35
+
36
+ <SmartSelect
37
+ bind:value={selectedValue}
38
+ {options}
39
+ searchable
40
+ placeholder="Select a language"
41
+ onchange={handleChange}
42
+ />
43
+ ```
44
+
45
+ ### AITextEditor
46
+
47
+ ```svelte
48
+ <script>
49
+ import { AITextEditor } from '@liwe3/webcomponents-svelte';
50
+
51
+ let content = $state('');
52
+ let systemPrompt = $state("You are a helpful writing assistant.");
53
+
54
+ const handleChange = (newValue) => {
55
+ console.log('Content changed:', newValue);
56
+ };
57
+ </script>
58
+
59
+ <AITextEditor
60
+ bind:value={content}
61
+ bind:systemPrompt
62
+ apiKey="your-api-key"
63
+ apiEndpoint="https://api.openai.com/v1/chat/completions"
64
+ modelName="gpt-3.5-turbo"
65
+ placeholder="Start writing..."
66
+ onchange={handleChange}
67
+ style="width: 100%; height: 400px;"
68
+ />
69
+ ```
70
+
71
+ ## Features
72
+
73
+ - **Full Svelte 5 Support**: Uses Svelte 5 runes (`$state`, `$bindable`, `$effect`)
74
+ - **TypeScript**: Full type safety
75
+ - **Reactive**: All props are reactive and two-way bindable where appropriate
76
+ - **SSR Safe**: Components are loaded dynamically to prevent SSR issues
77
+
78
+ ## Components
79
+
80
+ ### SmartSelect Props
81
+
82
+ - `multiple` (boolean): Enable multi-select mode
83
+ - `searchable` (boolean): Enable search functionality
84
+ - `placeholder` (string): Placeholder text
85
+ - `disabled` (boolean): Disable the select
86
+ - `value` (string | string[], bindable): Selected value(s)
87
+ - `options` (SelectOption[]): Array of `{value, label}` objects
88
+ - `onchange` (function): Change event handler
89
+ - `onopen` (function): Open event handler
90
+ - `onclose` (function): Close event handler
91
+ - `onsearch` (function): Search event handler
92
+
93
+ ### AITextEditor Props
94
+
95
+ - `value` (string, bindable): Editor content
96
+ - `apiKey` (string): API key for AI service
97
+ - `suggestionDelay` (number): Delay before showing suggestions (ms)
98
+ - `systemPrompt` (string, bindable): System prompt for AI
99
+ - `apiEndpoint` (string): API endpoint URL
100
+ - `modelName` (string): Model name to use
101
+ - `placeholder` (string): Placeholder text
102
+ - `onbeforesuggestion` (function): Called before requesting suggestion
103
+ - `onchange` (function): Change event handler
104
+
105
+ ## License
106
+
107
+ MIT
108
+
109
+ ## Links
110
+
111
+ - [Core Package](https://www.npmjs.com/package/@liwe3/webcomponents)
112
+ - [GitHub Repository](https://github.com/liwe3/webcomponents)
@@ -0,0 +1,151 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+
4
+ interface Props {
5
+ value?: string;
6
+ apiKey?: string;
7
+ suggestionDelay?: number;
8
+ systemPrompt?: string;
9
+ apiEndpoint?: string;
10
+ modelName?: string;
11
+ placeholder?: string;
12
+
13
+ onbeforesuggestion?: (data: any) => boolean;
14
+ onchange?: (value: string) => void;
15
+ }
16
+
17
+ let {
18
+ value = $bindable(''),
19
+ apiKey = '',
20
+ suggestionDelay = 3000,
21
+ systemPrompt = $bindable(
22
+ "You are a helpful writing assistant. Continue the user's text naturally and coherently. Provide 1-3 sentences that would logically follow their writing. Keep the same tone and style. Do not repeat what they've already written."
23
+ ),
24
+ apiEndpoint = 'https://api.openai.com/v1/chat/completions',
25
+ modelName = 'gpt-3.5-turbo',
26
+ placeholder = 'Start writing your markdown text here...',
27
+
28
+ onbeforesuggestion,
29
+ onchange
30
+ } = $props();
31
+
32
+ let elementRef: HTMLElement;
33
+ let webComponent: any;
34
+
35
+ /**
36
+ * Updates the web component property and syncs with Svelte state
37
+ */
38
+ const updateWebComponentProperty = (
39
+ propertyName: string,
40
+ newValue: any,
41
+ setterMethod?: string
42
+ ) => {
43
+ if (!webComponent) return;
44
+
45
+ const method =
46
+ setterMethod || `set${propertyName.charAt(0).toUpperCase() + propertyName.slice(1)}`;
47
+ if (typeof webComponent[method] === 'function') {
48
+ webComponent[method](newValue);
49
+ } else if (propertyName in webComponent) {
50
+ webComponent[propertyName] = newValue;
51
+ }
52
+ };
53
+
54
+ /**
55
+ * Syncs all props with the web component
56
+ */
57
+ const syncAllProps = () => {
58
+ if (!webComponent) return;
59
+
60
+ updateWebComponentProperty('apiKey', apiKey);
61
+ updateWebComponentProperty('suggestionDelay', suggestionDelay);
62
+ updateWebComponentProperty('systemPrompt', systemPrompt);
63
+ updateWebComponentProperty('apiEndpoint', apiEndpoint);
64
+ updateWebComponentProperty('modelName', modelName);
65
+
66
+ // Set initial text value
67
+ if (value && webComponent.getText() !== value) {
68
+ webComponent.setText(value);
69
+ }
70
+
71
+ // Set placeholder
72
+ const textarea = webComponent.shadowRoot?.getElementById('editor');
73
+ if (textarea && placeholder) {
74
+ textarea.placeholder = placeholder;
75
+ }
76
+ };
77
+
78
+ $effect(() => {
79
+ if (webComponent && webComponent.getText() !== value) {
80
+ webComponent.setText(value);
81
+ }
82
+ });
83
+
84
+ $effect(() => {
85
+ if (webComponent) {
86
+ const textarea = webComponent.shadowRoot?.getElementById('editor');
87
+ if (textarea && placeholder) {
88
+ textarea.placeholder = placeholder;
89
+ }
90
+ }
91
+ });
92
+
93
+ onMount(async () => {
94
+ // Dynamically import the web component
95
+ await import('@liwe3/webcomponents/ai-text-editor');
96
+
97
+ // Get reference to the web component
98
+ webComponent = elementRef;
99
+
100
+ // Sync all initial props
101
+ syncAllProps();
102
+
103
+ // Listen for changes from the web component
104
+ const handleChange = (event: CustomEvent) => {
105
+ const newValue = event.detail.value;
106
+ if (newValue !== value) {
107
+ value = newValue;
108
+ onchange?.(newValue);
109
+ }
110
+ };
111
+
112
+ // Forward beforeSuggestion event and allow parent to cancel
113
+ const handleBeforeSuggestion = (event: CustomEvent) => {
114
+ const cancel = onbeforesuggestion ? onbeforesuggestion(event.detail) : false;
115
+
116
+ // propagate cancellation back to the underlying web component
117
+ if (cancel) event.preventDefault();
118
+ };
119
+
120
+ webComponent.addEventListener('change', handleChange);
121
+ webComponent.addEventListener('beforeSuggestion', handleBeforeSuggestion as EventListener);
122
+
123
+ // Cleanup
124
+ return () => {
125
+ webComponent?.removeEventListener('change', handleChange);
126
+ webComponent?.removeEventListener(
127
+ 'beforeSuggestion',
128
+ handleBeforeSuggestion as EventListener
129
+ );
130
+ };
131
+ });
132
+
133
+ // Public methods to expose web component functionality
134
+ export const setText = (text: string) => {
135
+ value = text;
136
+ webComponent?.setText(text);
137
+ };
138
+
139
+ // Expose setContext to parent components
140
+ export const setContext = (context: string) => {
141
+ webComponent?.setContext(context);
142
+ };
143
+
144
+ // Expose setSystemPrompt to allow changing the system prompt dynamically
145
+ export const setSystemPrompt = (prompt: string) => {
146
+ systemPrompt = prompt;
147
+ webComponent?.setSystemPrompt?.(prompt);
148
+ };
149
+ </script>
150
+
151
+ <liwe3-ai-text-editor bind:this={elementRef}></liwe3-ai-text-editor>
@@ -0,0 +1,18 @@
1
+ declare const AITextEditor: import("svelte").Component<{
2
+ value?: string;
3
+ apiKey?: string;
4
+ suggestionDelay?: number;
5
+ systemPrompt?: string;
6
+ apiEndpoint?: string;
7
+ modelName?: string;
8
+ placeholder?: string;
9
+ onbeforesuggestion: any;
10
+ onchange: any;
11
+ }, {
12
+ setText: (text: string) => void;
13
+ setContext: (context: string) => void;
14
+ setSystemPrompt: (prompt: string) => void;
15
+ }, "value" | "systemPrompt">;
16
+ type AITextEditor = ReturnType<typeof AITextEditor>;
17
+ export default AITextEditor;
18
+ //# sourceMappingURL=AITextEditor.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AITextEditor.svelte.d.ts","sourceRoot":"","sources":["../src/lib/AITextEditor.svelte.ts"],"names":[],"mappings":"AA+JA,QAAA,MAAM,YAAY;YA5IqC,MAAM;aAAW,MAAM;sBAAoB,MAAM;mBAAiB,MAAM;kBAAgB,MAAM;gBAAc,MAAM;kBAAgB,MAAM;wBAAsB,GAAG;cAAY,GAAG;;oBAuH9M,MAAM;0BAMA,MAAM;8BAKF,MAAM;4BAUiB,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,148 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import type { SelectOption } from '@liwe3/webcomponents';
4
+
5
+ interface Props {
6
+ multiple?: boolean;
7
+ searchable?: boolean;
8
+ placeholder?: string;
9
+ disabled?: boolean;
10
+ value?: string | string[];
11
+ options?: SelectOption[];
12
+ onchange?: (value: string | string[] | undefined) => void;
13
+ onopen?: (event: CustomEvent) => void;
14
+ onclose?: (event: CustomEvent) => void;
15
+ onsearch?: (event: CustomEvent) => void;
16
+ }
17
+
18
+ let {
19
+ multiple = false,
20
+ searchable = false,
21
+ placeholder = 'Select an option',
22
+ disabled = false,
23
+ value = $bindable(),
24
+ options = [],
25
+ onchange,
26
+ onopen,
27
+ onclose,
28
+ onsearch,
29
+ ...restProps
30
+ }: Props = $props();
31
+
32
+ let smartSelectElement: HTMLElement;
33
+
34
+ /**
35
+ * Updates the web component's attributes based on props
36
+ */
37
+ const updateAttributes = () => {
38
+ if (!smartSelectElement) return;
39
+
40
+ // Set boolean attributes
41
+ if (multiple) {
42
+ smartSelectElement.setAttribute('multiple', '');
43
+ } else {
44
+ smartSelectElement.removeAttribute('multiple');
45
+ }
46
+
47
+ if (searchable) {
48
+ smartSelectElement.setAttribute('searchable', '');
49
+ } else {
50
+ smartSelectElement.removeAttribute('searchable');
51
+ }
52
+
53
+ if (disabled) {
54
+ smartSelectElement.setAttribute('disabled', '');
55
+ } else {
56
+ smartSelectElement.removeAttribute('disabled');
57
+ }
58
+
59
+ // Set string attributes
60
+ smartSelectElement.setAttribute('placeholder', placeholder);
61
+
62
+ // Set options as JSON string
63
+ if (options.length > 0) {
64
+ smartSelectElement.setAttribute('options', JSON.stringify(options));
65
+ }
66
+
67
+ // Set value
68
+ if (value !== undefined && value !== null) {
69
+ if (Array.isArray(value)) {
70
+ (smartSelectElement as any).value = value;
71
+ } else {
72
+ (smartSelectElement as any).value = value;
73
+ }
74
+ }
75
+ };
76
+
77
+ /**
78
+ * Binds event listeners to the web component
79
+ */
80
+ const bindEvents = () => {
81
+ if (!smartSelectElement) return;
82
+
83
+ smartSelectElement.addEventListener('change', (event) => {
84
+ const customEvent = event as CustomEvent;
85
+ value = customEvent.detail.value;
86
+ onchange?.(value);
87
+ });
88
+
89
+ smartSelectElement.addEventListener('open', (event) => {
90
+ onopen?.(event as CustomEvent);
91
+ });
92
+
93
+ smartSelectElement.addEventListener('close', (event) => {
94
+ onclose?.(event as CustomEvent);
95
+ });
96
+
97
+ smartSelectElement.addEventListener('search', (event) => {
98
+ onsearch?.(event as CustomEvent);
99
+ });
100
+ };
101
+
102
+ onMount(async () => {
103
+ // Dynamically import the web component
104
+ await import('@liwe3/webcomponents/smart-select');
105
+
106
+ updateAttributes();
107
+ bindEvents();
108
+
109
+ // Watch for prop changes and update attributes
110
+ $effect(() => {
111
+ updateAttributes();
112
+ });
113
+ });
114
+
115
+ /**
116
+ * Expose methods to parent component
117
+ */
118
+ export const open = () => {
119
+ (smartSelectElement as any)?.open();
120
+ };
121
+
122
+ export const close = () => {
123
+ (smartSelectElement as any)?.close();
124
+ };
125
+
126
+ export const toggle = () => {
127
+ (smartSelectElement as any)?.toggle();
128
+ };
129
+
130
+ export const selectOption = (optionValue: string) => {
131
+ (smartSelectElement as any)?.selectOption(optionValue);
132
+ };
133
+
134
+ export const deselectOption = (optionValue: string) => {
135
+ (smartSelectElement as any)?.deselectOption(optionValue);
136
+ };
137
+
138
+ export const getSelectedOptions = () => {
139
+ return (smartSelectElement as any)?.getSelectedOptions() || [];
140
+ };
141
+
142
+ export const setOptions = (newOptions: SelectOption[]) => {
143
+ (smartSelectElement as any)?.setOptions(newOptions);
144
+ };
145
+ </script>
146
+
147
+ <!-- svelte-ignore a11y_unknown_aria_attribute -->
148
+ <liwe3-select bind:this={smartSelectElement} {...restProps}></liwe3-select>
@@ -0,0 +1,27 @@
1
+ import type { SelectOption } from '@liwe3/webcomponents';
2
+ interface Props {
3
+ multiple?: boolean;
4
+ searchable?: boolean;
5
+ placeholder?: string;
6
+ disabled?: boolean;
7
+ value?: string | string[];
8
+ options?: SelectOption[];
9
+ onchange?: (value: string | string[] | undefined) => void;
10
+ onopen?: (event: CustomEvent) => void;
11
+ onclose?: (event: CustomEvent) => void;
12
+ onsearch?: (event: CustomEvent) => void;
13
+ }
14
+ declare const SmartSelect: import("svelte").Component<Props, {
15
+ /**
16
+ * Expose methods to parent component
17
+ */ open: () => void;
18
+ close: () => void;
19
+ toggle: () => void;
20
+ selectOption: (optionValue: string) => void;
21
+ deselectOption: (optionValue: string) => void;
22
+ getSelectedOptions: () => any;
23
+ setOptions: (newOptions: SelectOption[]) => void;
24
+ }, "value">;
25
+ type SmartSelect = ReturnType<typeof SmartSelect>;
26
+ export default SmartSelect;
27
+ //# sourceMappingURL=SmartSelect.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartSelect.svelte.d.ts","sourceRoot":"","sources":["../src/lib/SmartSelect.svelte.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGxD,UAAU,KAAK;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CACxC;AA+IF,QAAA,MAAM,WAAW;IAHjB;;WAEI;;;gCAxBiC,MAAM;kCAIJ,MAAM;;6BAQX,YAAY,EAAE;WAaS,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @liwe3/webcomponents-svelte
3
+ * Svelte 5 wrappers for @liwe3/webcomponents
4
+ */
5
+ export type { SelectOption, AITextEditorConfig } from '@liwe3/webcomponents';
6
+ export { default as SmartSelect } from './SmartSelect.svelte';
7
+ export { default as AITextEditor } from './AITextEditor.svelte';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/lib/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAG7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @liwe3/webcomponents-svelte
3
+ * Svelte 5 wrappers for @liwe3/webcomponents
4
+ */
5
+ // Export Svelte components
6
+ export { default as SmartSelect } from './SmartSelect.svelte';
7
+ export { default as AITextEditor } from './AITextEditor.svelte';
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@liwe3/webcomponents-svelte",
3
+ "version": "1.0.0",
4
+ "description": "Svelte 5 wrappers for @liwe3/webcomponents",
5
+ "type": "module",
6
+ "svelte": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "svelte": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "!dist/**/*.test.*",
17
+ "!dist/**/*.spec.*"
18
+ ],
19
+ "scripts": {
20
+ "build": "svelte-package -i src/lib",
21
+ "package": "svelte-package -i src/lib && publint",
22
+ "prepublishOnly": "pnpm run package",
23
+ "check": "svelte-check --tsconfig ./tsconfig.json",
24
+ "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch"
25
+ },
26
+ "keywords": [
27
+ "svelte",
28
+ "svelte5",
29
+ "web-components",
30
+ "components",
31
+ "liwe3",
32
+ "smart-select",
33
+ "ai-text-editor"
34
+ ],
35
+ "author": "Liwe3",
36
+ "license": "MIT",
37
+ "peerDependencies": {
38
+ "@liwe3/webcomponents": "^1.0.0",
39
+ "svelte": "^5.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@liwe3/webcomponents": "workspace:*",
43
+ "@sveltejs/package": "^2.0.0",
44
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
45
+ "publint": "^0.2.0",
46
+ "svelte": "^5.38.10",
47
+ "svelte-check": "^4.0.0",
48
+ "typescript": "^5.9.2",
49
+ "vite": "^7.0.0"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public"
53
+ },
54
+ "packageManager": "pnpm@10.16.0"
55
+ }