@finsweet/webflow-apps-utils 1.0.3 → 1.0.5

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.
Files changed (116) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/providers/GlobalProvider.stories.d.ts +5 -0
  4. package/dist/providers/GlobalProvider.stories.js +419 -0
  5. package/dist/providers/GlobalProviderDemo.svelte +266 -0
  6. package/dist/providers/GlobalProviderDemo.svelte.d.ts +3 -0
  7. package/dist/providers/configuratorUtils.d.ts +11 -14
  8. package/dist/providers/configuratorUtils.js +68 -115
  9. package/dist/providers/index.d.ts +1 -1
  10. package/dist/providers/index.js +1 -1
  11. package/dist/router/Router.stories.d.ts +6 -0
  12. package/dist/router/Router.stories.js +564 -0
  13. package/dist/router/examples/RouterExample.svelte +271 -0
  14. package/dist/router/examples/RouterExample.svelte.d.ts +18 -0
  15. package/dist/router/examples/index.d.ts +4 -0
  16. package/dist/router/examples/index.js +4 -0
  17. package/dist/router/examples/pages/AboutPage.svelte +568 -0
  18. package/dist/router/examples/pages/AboutPage.svelte.d.ts +13 -0
  19. package/dist/router/examples/pages/HomePage.svelte +200 -0
  20. package/dist/router/examples/pages/HomePage.svelte.d.ts +14 -0
  21. package/dist/router/examples/pages/NotFoundPage.svelte +307 -0
  22. package/dist/router/examples/pages/NotFoundPage.svelte.d.ts +17 -0
  23. package/dist/router/hooks.svelte.d.ts +2 -2
  24. package/dist/router/index.d.ts +3 -0
  25. package/dist/router/index.js +3 -0
  26. package/dist/router/{Link.svelte → providers/Link.svelte} +1 -1
  27. package/dist/router/{Route.svelte → providers/Route.svelte} +1 -1
  28. package/dist/router/{Route.svelte.d.ts → providers/Route.svelte.d.ts} +1 -1
  29. package/dist/router/{Router.svelte → providers/RouterProvider.svelte} +22 -5
  30. package/dist/router/{Router.svelte.d.ts → providers/RouterProvider.svelte.d.ts} +8 -4
  31. package/dist/router/providers/index.d.ts +3 -0
  32. package/dist/router/providers/index.js +3 -0
  33. package/dist/router/{index.svelte.d.ts → router.svelte.d.ts} +1 -3
  34. package/dist/router/{index.svelte.js → router.svelte.js} +1 -4
  35. package/dist/stores/forms/Form.stories.d.ts +5 -0
  36. package/dist/stores/forms/Form.stories.js +342 -0
  37. package/dist/stores/forms/FormDemo.svelte +545 -0
  38. package/dist/stores/forms/FormDemo.svelte.d.ts +18 -0
  39. package/dist/stores/forms.d.ts +41 -4
  40. package/dist/stores/forms.js +86 -32
  41. package/dist/types/customCode.d.ts +1 -1
  42. package/dist/types/window.d.ts +1 -0
  43. package/dist/ui/components/button/Button.svelte +1 -1
  44. package/dist/ui/components/copy-text/CopyText.stories.d.ts +70 -0
  45. package/dist/ui/components/copy-text/CopyText.stories.js +241 -0
  46. package/dist/ui/components/copy-text/CopyText.svelte +247 -0
  47. package/dist/ui/components/copy-text/CopyText.svelte.d.ts +4 -0
  48. package/dist/ui/components/copy-text/index.d.ts +2 -0
  49. package/dist/ui/components/copy-text/index.js +1 -0
  50. package/dist/ui/components/copy-text/types.d.ts +52 -0
  51. package/dist/ui/components/copy-text/types.js +1 -0
  52. package/dist/ui/components/index.d.ts +1 -0
  53. package/dist/ui/components/index.js +1 -0
  54. package/dist/ui/components/input/Input.stories.d.ts +9 -0
  55. package/dist/ui/components/input/Input.stories.js +78 -0
  56. package/dist/ui/components/input/Input.svelte +39 -3
  57. package/dist/ui/components/input/types.d.ts +6 -0
  58. package/dist/ui/components/layout/Layout.svelte +45 -64
  59. package/dist/ui/components/layout/Layout.svelte.d.ts +26 -3
  60. package/dist/ui/components/layout/examples/ExampleLayout.svelte +32 -27
  61. package/dist/ui/components/layout/index.d.ts +1 -1
  62. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte +20 -0
  63. package/dist/ui/components/layout/test-helpers/TestLayoutWithFooter.svelte.d.ts +7 -0
  64. package/dist/ui/components/layout/types.d.ts +1 -10
  65. package/dist/ui/components/notification/Notification.stories.svelte +12 -1
  66. package/dist/ui/components/notification/Notification.svelte +10 -5
  67. package/dist/ui/components/notification/Notification.svelte.d.ts +1 -1
  68. package/dist/ui/components/notification/types.d.ts +1 -1
  69. package/dist/ui/components/section/Section.svelte +8 -4
  70. package/dist/ui/components/section/types.d.ts +8 -0
  71. package/dist/ui/components/text/Text.stories.svelte +67 -1
  72. package/dist/ui/components/text/Text.svelte +209 -8
  73. package/dist/ui/components/text/types.d.ts +4 -0
  74. package/dist/ui/index.css +6 -2
  75. package/dist/utils/animations/factory.d.ts +7 -0
  76. package/dist/utils/animations/factory.js +101 -0
  77. package/dist/utils/animations/index.d.ts +7 -0
  78. package/dist/utils/animations/index.js +62 -0
  79. package/dist/utils/animations/types.d.ts +39 -0
  80. package/dist/utils/animations/types.js +1 -0
  81. package/dist/utils/custom-code/configs.d.ts +22 -0
  82. package/dist/utils/custom-code/configs.js +40 -0
  83. package/dist/utils/custom-code/index.d.ts +1 -0
  84. package/dist/utils/custom-code/index.js +1 -0
  85. package/dist/utils/diff-mapper/DiffMapper.stories.d.ts +5 -0
  86. package/dist/utils/diff-mapper/DiffMapper.stories.js +185 -0
  87. package/dist/utils/diff-mapper/DiffMapperDemo.svelte +351 -0
  88. package/dist/utils/diff-mapper/DiffMapperDemo.svelte.d.ts +18 -0
  89. package/dist/utils/diff-mapper/deepDiffMapper.d.ts +31 -0
  90. package/dist/utils/diff-mapper/deepDiffMapper.js +264 -0
  91. package/dist/utils/diff-mapper/index.d.ts +1 -0
  92. package/dist/utils/diff-mapper/index.js +1 -0
  93. package/dist/utils/helpers/capitalizeFirstLetter.d.ts +4 -0
  94. package/dist/utils/helpers/capitalizeFirstLetter.js +9 -0
  95. package/dist/utils/helpers/getTimeNow.d.ts +4 -0
  96. package/dist/utils/helpers/getTimeNow.js +8 -0
  97. package/dist/utils/helpers/index.d.ts +4 -0
  98. package/dist/utils/helpers/index.js +4 -0
  99. package/dist/utils/helpers/minifyCode.d.ts +10 -0
  100. package/dist/utils/helpers/minifyCode.js +73 -0
  101. package/dist/utils/helpers/objectsToModuleExports.d.ts +1 -1
  102. package/dist/utils/helpers/objectsToModuleExports.js +1 -0
  103. package/dist/utils/helpers/toHumanReadableList.d.ts +4 -0
  104. package/dist/utils/helpers/toHumanReadableList.js +11 -0
  105. package/dist/utils/index.d.ts +2 -0
  106. package/dist/utils/index.js +2 -0
  107. package/dist/utils/webflow-canvas/getAllChildren.d.ts +16 -0
  108. package/dist/utils/webflow-canvas/getAllChildren.js +65 -0
  109. package/dist/utils/webflow-canvas/getElementClassList.d.ts +9 -0
  110. package/dist/utils/webflow-canvas/getElementClassList.js +19 -0
  111. package/dist/utils/webflow-canvas/index.d.ts +2 -0
  112. package/dist/utils/webflow-canvas/index.js +2 -0
  113. package/package.json +6 -1
  114. package/dist/providers/GlobalProvider.mdx +0 -322
  115. package/dist/router/README.md +0 -397
  116. /package/dist/router/{Link.svelte.d.ts → providers/Link.svelte.d.ts} +0 -0
@@ -6,18 +6,25 @@ const formsRegistry = writable({});
6
6
  // Validates class name according to HTML class name rules
7
7
  const classNameRegex = /^[a-zA-Z0-9_-]+$/;
8
8
  /**
9
- * Creates a form validation utility with Zod
9
+ * Creates a form validation utility with Svelte 5 reactive stores
10
10
  * @param identifier - Unique identifier for the form
11
11
  * @param options - Configuration options
12
12
  */
13
13
  export class FormValidator {
14
14
  schema;
15
- store;
16
- form;
15
+ _store;
17
16
  instancesSet = new Set();
18
17
  initialValues;
19
18
  identifier;
20
19
  currentInstanceToIgnore = null;
20
+ classValidationEnabled = true;
21
+ // Public reactive stores that components can directly use
22
+ values;
23
+ errors;
24
+ touched;
25
+ isValid;
26
+ isDirty;
27
+ isSubmitting;
21
28
  /**
22
29
  * Generates unique name, instance, and class based on solution name and existing instances
23
30
  * @param existingInstances - Array of existing instance names
@@ -86,8 +93,8 @@ export class FormValidator {
86
93
  if (options?.existingInstances) {
87
94
  options.existingInstances.forEach((instance) => this.instancesSet.add(instance.toLowerCase()));
88
95
  }
89
- // Create the form state store
90
- this.store = writable({
96
+ // Create the internal form state store
97
+ this._store = writable({
91
98
  values: initialValues,
92
99
  errors: {},
93
100
  touched: {},
@@ -96,7 +103,12 @@ export class FormValidator {
96
103
  isSubmitting: false
97
104
  });
98
105
  // Create a derived store that's the primary interface to the form
99
- this.form = derived(this.store, ($store) => $store);
106
+ this.values = derived(this._store, ($store) => $store.values);
107
+ this.errors = derived(this._store, ($store) => $store.errors);
108
+ this.touched = derived(this._store, ($store) => $store.touched);
109
+ this.isValid = derived(this._store, ($store) => $store.isValid);
110
+ this.isDirty = derived(this._store, ($store) => $store.isDirty);
111
+ this.isSubmitting = derived(this._store, ($store) => $store.isSubmitting);
100
112
  // Register this form with the global registry
101
113
  formsRegistry.update((registry) => {
102
114
  registry[identifier] = this;
@@ -120,7 +132,7 @@ export class FormValidator {
120
132
  * Set the value of a specific field
121
133
  */
122
134
  setField(field, value) {
123
- this.store.update((state) => {
135
+ this._store.update((state) => {
124
136
  const newState = {
125
137
  ...state,
126
138
  values: {
@@ -141,7 +153,7 @@ export class FormValidator {
141
153
  * Set multiple field values at once
142
154
  */
143
155
  setFields(values) {
144
- this.store.update((state) => {
156
+ this._store.update((state) => {
145
157
  const newTouched = { ...state.touched };
146
158
  // Mark all updated fields as touched
147
159
  Object.keys(values).forEach((key) => {
@@ -171,7 +183,7 @@ export class FormValidator {
171
183
  * Reset the form to initial values
172
184
  */
173
185
  reset() {
174
- this.store.set({
186
+ this._store.set({
175
187
  values: { ...this.initialValues },
176
188
  errors: {},
177
189
  touched: {},
@@ -181,32 +193,46 @@ export class FormValidator {
181
193
  });
182
194
  this.validate();
183
195
  }
196
+ /**
197
+ * Enable or disable class name validation
198
+ * @param enabled - Whether to enable class validation
199
+ */
200
+ enableClassValidation(enabled) {
201
+ this.classValidationEnabled = enabled;
202
+ this.validate();
203
+ }
184
204
  /**
185
205
  * Validate the form values
186
206
  */
187
207
  validate() {
188
- this.store.update((state) => {
189
- // Create a custom schema for validation that includes instance uniqueness
190
- const currentSchema = z.object({
191
- name: z.string().min(1, { message: 'Name is required' }),
192
- instance: z
193
- .string()
194
- .min(1, { message: 'Instance is required' })
195
- .refine((value) => {
196
- // Skip if empty (handled by min(1) above)
197
- if (!value)
198
- return true;
199
- // If we're in edit mode and this is the current instance, skip duplicate validation
200
- if (this.currentInstanceToIgnore &&
201
- value.toLowerCase() === this.currentInstanceToIgnore) {
202
- return true;
203
- }
204
- // Check for uniqueness against the set of existing instances
205
- return !this.instancesSet.has(value.toLowerCase());
206
- }, { message: 'Instance name must be unique' }),
207
- class: z.string().min(1, { message: 'Class is required' }).regex(classNameRegex, {
208
+ this._store.update((state) => {
209
+ // Create a custom schema for validation that includes instance uniqueness and conditional class validation
210
+ const nameSchema = z.string().min(1, { message: 'Name is required' });
211
+ const instanceSchema = z
212
+ .string()
213
+ .min(1, { message: 'Instance is required' })
214
+ .refine((value) => {
215
+ // Skip if empty (handled by min(1) above)
216
+ if (!value)
217
+ return true;
218
+ // If we're in edit mode and this is the current instance, skip duplicate validation
219
+ if (this.currentInstanceToIgnore &&
220
+ value.toLowerCase() === this.currentInstanceToIgnore) {
221
+ return true;
222
+ }
223
+ // Check for uniqueness against the set of existing instances
224
+ return !this.instancesSet.has(value.toLowerCase());
225
+ }, { message: 'Instance name must be unique' });
226
+ // Conditionally create class validation
227
+ const classSchema = this.classValidationEnabled
228
+ ? z.string().min(1, { message: 'Class is required' }).regex(classNameRegex, {
208
229
  message: 'Class must contain only letters, numbers, underscores, and hyphens'
209
230
  })
231
+ : z.string();
232
+ const currentSchema = z.object({
233
+ name: nameSchema,
234
+ instance: instanceSchema,
235
+ class: classSchema
210
236
  });
211
237
  // Validate the current values against the schema
212
238
  const result = currentSchema.safeParse(state.values);
@@ -233,18 +259,46 @@ export class FormValidator {
233
259
  * Set the form as submitting
234
260
  */
235
261
  setSubmitting(isSubmitting) {
236
- this.store.update((state) => ({
262
+ this._store.update((state) => ({
237
263
  ...state,
238
264
  isSubmitting
239
265
  }));
240
266
  }
241
267
  /**
242
- * Get the current state of the form
268
+ * Get the current state of the form (for legacy compatibility)
243
269
  */
244
270
  getState() {
245
- return get(this.store);
271
+ return get(this._store);
246
272
  }
247
273
  }
274
+ /**
275
+ * Setup form hook
276
+ */
277
+ export function createForm(identifier, initialValues, options) {
278
+ const form = new FormValidator(identifier, initialValues, options);
279
+ if (options?.enableClassValidation !== undefined) {
280
+ form.enableClassValidation(options.enableClassValidation);
281
+ }
282
+ return {
283
+ // Reactive stores that components can directly subscribe to
284
+ values: form.values,
285
+ errors: form.errors,
286
+ touched: form.touched,
287
+ isValid: form.isValid,
288
+ isDirty: form.isDirty,
289
+ isSubmitting: form.isSubmitting,
290
+ // Helper methods
291
+ setField: form.setField.bind(form),
292
+ setFields: form.setFields.bind(form),
293
+ reset: form.reset.bind(form),
294
+ enableClassValidation: form.enableClassValidation.bind(form),
295
+ ignoreInstanceValidation: form.ignoreInstanceValidation.bind(form),
296
+ setSubmitting: form.setSubmitting.bind(form),
297
+ // For advanced use cases
298
+ validate: () => form.validateWithInstances(options?.existingInstances || []),
299
+ getState: form.getState.bind(form)
300
+ };
301
+ }
248
302
  /**
249
303
  * Get a form by its identifier
250
304
  */
@@ -2,7 +2,7 @@ interface CustomCodeAttributes {
2
2
  async: string;
3
3
  type: string;
4
4
  siteId: string;
5
- finsweet: 'components';
5
+ finsweet: 'components' | 'cmp' | 'fast-search';
6
6
  }
7
7
  export interface CustomCodeBlock {
8
8
  id?: string;
@@ -9,6 +9,7 @@ declare global {
9
9
  event: string;
10
10
  } | IArguments>;
11
11
  Webflow?: Webflow | WebflowCallback[];
12
+ isLoadingCustomCodeConfigs: boolean;
12
13
  }
13
14
  }
14
15
  export type ALLOWED_BREAKPOINTS = '320' | '480' | '768' | '991' | '1280' | '1440' | '1920';
@@ -125,7 +125,7 @@
125
125
  let shouldShowTooltip = $derived(!!tooltip?.message || !!tooltip?.tooltipContent);
126
126
 
127
127
  // Default styling (no size variations)
128
- let computedPadding = $derived(padding || '4px');
128
+ let computedPadding = $derived(padding || '4px 8px');
129
129
  let computedIconSize = $derived(iconSize);
130
130
 
131
131
  // Computed classes
@@ -0,0 +1,70 @@
1
+ import type { StoryObj } from '@storybook/sveltekit';
2
+ import type { CopyTextProps } from './types.js';
3
+ declare const meta: {
4
+ title: string;
5
+ component: import("svelte").Component<CopyTextProps, {}, "">;
6
+ parameters: {
7
+ layout: string;
8
+ docs: {
9
+ description: {
10
+ component: string;
11
+ };
12
+ };
13
+ };
14
+ tags: string[];
15
+ argTypes: {
16
+ content: {
17
+ control: "text";
18
+ description: string;
19
+ };
20
+ title: {
21
+ control: "text";
22
+ description: string;
23
+ };
24
+ disabled: {
25
+ control: "boolean";
26
+ description: string;
27
+ };
28
+ raw: {
29
+ control: "boolean";
30
+ description: string;
31
+ };
32
+ hidden: {
33
+ control: "boolean";
34
+ description: string;
35
+ };
36
+ comment: {
37
+ control: "text";
38
+ description: string;
39
+ };
40
+ tooltip: {
41
+ control: "text";
42
+ description: string;
43
+ };
44
+ class: {
45
+ control: "text";
46
+ description: string;
47
+ };
48
+ };
49
+ };
50
+ export default meta;
51
+ type Story = StoryObj<typeof meta>;
52
+ export declare const Default: Story;
53
+ export declare const WithTitle: Story;
54
+ export declare const Disabled: Story;
55
+ export declare const RawContent: Story;
56
+ export declare const RawContentWithComment: Story;
57
+ export declare const MultilineContent: Story;
58
+ export declare const LongContent: Story;
59
+ export declare const CustomTooltip: Story;
60
+ export declare const WithNotifications: Story;
61
+ export declare const HTMLSnippet: Story;
62
+ export declare const CSSCode: Story;
63
+ export declare const JSONData: Story;
64
+ export declare const CopiedState: Story;
65
+ export declare const WithCustomStyles: Story;
66
+ export declare const EmptyContent: Story;
67
+ export declare const SpecialCharacters: Story;
68
+ export declare const InstallCommand: Story;
69
+ export declare const GitClone: Story;
70
+ export declare const APIEndpoint: Story;
@@ -0,0 +1,241 @@
1
+ import CopyText from './CopyText.svelte';
2
+ const meta = {
3
+ title: 'Ui/CopyText',
4
+ component: CopyText,
5
+ parameters: {
6
+ layout: 'centered',
7
+ docs: {
8
+ description: {
9
+ component: 'A reusable copy-to-clipboard component that handles text copying with visual feedback and optional notifications. Built with Svelte 5 runes and proper TypeScript support.'
10
+ }
11
+ }
12
+ },
13
+ tags: ['autodocs'],
14
+ argTypes: {
15
+ content: {
16
+ control: 'text',
17
+ description: 'The content to be copied to clipboard'
18
+ },
19
+ title: {
20
+ control: 'text',
21
+ description: 'Optional title/heading text to display above the copy area'
22
+ },
23
+ disabled: {
24
+ control: 'boolean',
25
+ description: 'Whether the copy functionality is disabled'
26
+ },
27
+ raw: {
28
+ control: 'boolean',
29
+ description: 'Whether to show the content in raw format (with HTML) or cleaned'
30
+ },
31
+ hidden: {
32
+ control: 'boolean',
33
+ description: 'Whether the component is in a hidden state'
34
+ },
35
+ comment: {
36
+ control: 'text',
37
+ description: 'Optional comment to prepend to copied content when in raw mode'
38
+ },
39
+ tooltip: {
40
+ control: 'text',
41
+ description: 'Custom tooltip text for the copy button'
42
+ },
43
+ class: {
44
+ control: 'text',
45
+ description: 'Custom CSS classes'
46
+ }
47
+ }
48
+ };
49
+ export default meta;
50
+ // Basic stories
51
+ export const Default = {
52
+ args: {
53
+ content: 'console.log("Hello, World!");'
54
+ }
55
+ };
56
+ export const WithTitle = {
57
+ args: {
58
+ content: 'npm install @your-org/ui-library',
59
+ title: 'Installation Command'
60
+ }
61
+ };
62
+ export const Disabled = {
63
+ args: {
64
+ content: 'This content cannot be copied',
65
+ title: 'Disabled Copy',
66
+ disabled: true
67
+ }
68
+ };
69
+ export const RawContent = {
70
+ args: {
71
+ content: '<script>\n console.log("Raw HTML/JS content");\n</script>',
72
+ title: 'Raw HTML/JavaScript',
73
+ raw: true
74
+ }
75
+ };
76
+ export const RawContentWithComment = {
77
+ args: {
78
+ content: '<script>\n // Your custom code here\n console.log("Hello from script!");\n</script>',
79
+ title: 'Script with Comment',
80
+ raw: true,
81
+ comment: 'Add this script to your site'
82
+ }
83
+ };
84
+ export const MultilineContent = {
85
+ args: {
86
+ content: `function greetUser(name) {
87
+ return \`Hello, \${name}! Welcome to our app.\`;
88
+ }
89
+
90
+ // Usage example
91
+ const greeting = greetUser('Alice');
92
+ console.log(greeting);`,
93
+ title: 'JavaScript Function',
94
+ tooltip: 'Copy this function to your clipboard'
95
+ }
96
+ };
97
+ export const LongContent = {
98
+ args: {
99
+ content: `// This is a very long line of code that demonstrates how the component handles content that exceeds the maximum width of the container and needs to wrap or scroll horizontally for better user experience and readability.
100
+ const veryLongVariableName = "This is a demonstration of very long content that might need horizontal scrolling";`,
101
+ title: 'Long Content Example'
102
+ }
103
+ };
104
+ export const CustomTooltip = {
105
+ args: {
106
+ content: 'secret-api-key-12345',
107
+ title: 'API Key',
108
+ tooltip: 'Click to copy your API key'
109
+ }
110
+ };
111
+ // Interactive examples with callbacks
112
+ export const WithNotifications = {
113
+ args: {
114
+ content: 'Content with notification feedback',
115
+ title: 'Copy with Notifications',
116
+ onNotify: (options) => {
117
+ // Simulate webflow.notify or any notification system
118
+ console.log(`${options.type}: ${options.message}`);
119
+ alert(`${options.type}: ${options.message}`);
120
+ },
121
+ onCopy: (content) => {
122
+ console.log('Copied:', content);
123
+ },
124
+ onError: (error) => {
125
+ console.error('Copy failed:', error);
126
+ }
127
+ }
128
+ };
129
+ // Different content types
130
+ export const HTMLSnippet = {
131
+ args: {
132
+ content: `<div class="banner">
133
+ <h1>Welcome to our site!</h1>
134
+ <p>This is a sample HTML snippet.</p>
135
+ </div>`,
136
+ title: 'HTML Snippet',
137
+ raw: true
138
+ }
139
+ };
140
+ export const CSSCode = {
141
+ args: {
142
+ content: `.button {
143
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
144
+ border: none;
145
+ border-radius: 8px;
146
+ padding: 12px 24px;
147
+ color: white;
148
+ cursor: pointer;
149
+ transition: transform 0.2s ease;
150
+ }
151
+
152
+ .button:hover {
153
+ transform: translateY(-2px);
154
+ }`,
155
+ title: 'CSS Styles'
156
+ }
157
+ };
158
+ export const JSONData = {
159
+ args: {
160
+ content: `{
161
+ "name": "CopyText Component",
162
+ "version": "1.0.0",
163
+ "description": "A reusable copy-to-clipboard component",
164
+ "features": [
165
+ "Svelte 5 runes",
166
+ "TypeScript support",
167
+ "Accessibility compliant",
168
+ "Customizable styling"
169
+ ]
170
+ }`,
171
+ title: 'JSON Configuration'
172
+ }
173
+ };
174
+ // State demonstrations
175
+ export const CopiedState = {
176
+ args: {
177
+ content: 'Content with callback notifications instead of visual styling',
178
+ title: 'Copy State Demo',
179
+ onNotify: (options) => {
180
+ alert(`${options.type}: ${options.message}`);
181
+ }
182
+ },
183
+ parameters: {
184
+ docs: {
185
+ description: {
186
+ story: 'After clicking copy, notifications are handled via callbacks rather than visual styling changes.'
187
+ }
188
+ }
189
+ }
190
+ };
191
+ export const WithCustomStyles = {
192
+ args: {
193
+ content: 'Styled copy text component',
194
+ title: 'Custom Styled',
195
+ class: 'custom-copy-text'
196
+ },
197
+ parameters: {
198
+ docs: {
199
+ description: {
200
+ story: 'The component accepts custom CSS classes for styling customization.'
201
+ }
202
+ }
203
+ }
204
+ };
205
+ // Edge cases
206
+ export const EmptyContent = {
207
+ args: {
208
+ content: '',
209
+ title: 'Empty Content'
210
+ }
211
+ };
212
+ export const SpecialCharacters = {
213
+ args: {
214
+ content: `Special chars: !@#$%^&*()_+-=[]{}|;':",./<>?
215
+ Unicode: 🚀 💻 🎉 ✨ 🔥
216
+ Escaped: "quotes" 'apostrophes' \\backslashes\\`,
217
+ title: 'Special Characters'
218
+ }
219
+ };
220
+ // Real-world examples
221
+ export const InstallCommand = {
222
+ args: {
223
+ content: 'npm install clipboard svelte @types/node',
224
+ title: 'Installation',
225
+ tooltip: 'Copy install command'
226
+ }
227
+ };
228
+ export const GitClone = {
229
+ args: {
230
+ content: 'git clone https://github.com/your-org/your-repo.git',
231
+ title: 'Clone Repository',
232
+ tooltip: 'Copy git clone command'
233
+ }
234
+ };
235
+ export const APIEndpoint = {
236
+ args: {
237
+ content: 'https://api.yourservice.com/v1/users',
238
+ title: 'API Endpoint',
239
+ tooltip: 'Copy API endpoint URL'
240
+ }
241
+ };