@finsweet/webflow-apps-utils 1.0.31 → 1.0.33
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/ui/components/select/Select.stories.d.ts +16 -0
- package/dist/ui/components/select/Select.stories.js +173 -0
- package/dist/ui/components/select/Select.svelte +166 -118
- package/dist/ui/components/select/types.d.ts +13 -0
- package/dist/ui/components/tooltip/Tooltip.svelte +2 -2
- package/dist/utils/webflow-canvas/getAllPages.d.ts +2 -2
- package/dist/utils/webflow-canvas/getAllPages.js +6 -5
- package/dist/utils/webflow-canvas/getSiteStagingUrl.js +5 -2
- package/package.json +1 -1
|
@@ -68,6 +68,14 @@ declare const meta: {
|
|
|
68
68
|
control: string;
|
|
69
69
|
description: string;
|
|
70
70
|
};
|
|
71
|
+
alert: {
|
|
72
|
+
control: string;
|
|
73
|
+
description: string;
|
|
74
|
+
};
|
|
75
|
+
invalid: {
|
|
76
|
+
control: string;
|
|
77
|
+
description: string;
|
|
78
|
+
};
|
|
71
79
|
};
|
|
72
80
|
};
|
|
73
81
|
export default meta;
|
|
@@ -92,3 +100,11 @@ export declare const SingleOption: Story;
|
|
|
92
100
|
export declare const LongOptions: Story;
|
|
93
101
|
export declare const AccessibilityTest: Story;
|
|
94
102
|
export declare const ManyOptions: Story;
|
|
103
|
+
export declare const WithErrorAlert: Story;
|
|
104
|
+
export declare const WithWarningAlert: Story;
|
|
105
|
+
export declare const WithSuccessAlert: Story;
|
|
106
|
+
export declare const WithInfoAlert: Story;
|
|
107
|
+
export declare const InvalidState: Story;
|
|
108
|
+
export declare const InvalidWithAlert: Story;
|
|
109
|
+
export declare const ValidationStates: Story;
|
|
110
|
+
export declare const FormValidationExample: Story;
|
|
@@ -114,6 +114,14 @@ const meta = {
|
|
|
114
114
|
className: {
|
|
115
115
|
control: 'text',
|
|
116
116
|
description: 'Additional CSS classes'
|
|
117
|
+
},
|
|
118
|
+
alert: {
|
|
119
|
+
control: 'object',
|
|
120
|
+
description: 'Alert configuration for validation messages'
|
|
121
|
+
},
|
|
122
|
+
invalid: {
|
|
123
|
+
control: 'boolean',
|
|
124
|
+
description: 'Whether the select is in an invalid state'
|
|
117
125
|
}
|
|
118
126
|
}
|
|
119
127
|
};
|
|
@@ -394,3 +402,168 @@ export const ManyOptions = {
|
|
|
394
402
|
}
|
|
395
403
|
}
|
|
396
404
|
};
|
|
405
|
+
// Validation and error states
|
|
406
|
+
export const WithErrorAlert = {
|
|
407
|
+
args: {
|
|
408
|
+
options: basicOptions,
|
|
409
|
+
defaultText: 'Select a required option',
|
|
410
|
+
alert: {
|
|
411
|
+
type: 'error',
|
|
412
|
+
message: 'This field is required. Please select an option.'
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
parameters: {
|
|
416
|
+
docs: {
|
|
417
|
+
description: {
|
|
418
|
+
story: 'Shows an error alert with a validation message. Hover over the select to see the tooltip.'
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
export const WithWarningAlert = {
|
|
424
|
+
args: {
|
|
425
|
+
options: basicOptions,
|
|
426
|
+
selected: 'option3',
|
|
427
|
+
defaultText: 'Select an option',
|
|
428
|
+
alert: {
|
|
429
|
+
type: 'warning',
|
|
430
|
+
message: 'This option may affect performance. Consider choosing a different option.'
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
parameters: {
|
|
434
|
+
docs: {
|
|
435
|
+
description: {
|
|
436
|
+
story: 'Warning alert to inform users about potential issues with their selection.'
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
export const WithSuccessAlert = {
|
|
442
|
+
args: {
|
|
443
|
+
options: basicOptions,
|
|
444
|
+
selected: 'option1',
|
|
445
|
+
defaultText: 'Select an option',
|
|
446
|
+
alert: {
|
|
447
|
+
type: 'success',
|
|
448
|
+
message: 'Great choice! This option is optimized for your use case.'
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
parameters: {
|
|
452
|
+
docs: {
|
|
453
|
+
description: {
|
|
454
|
+
story: 'Success alert to confirm a good selection or provide positive feedback.'
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
export const WithInfoAlert = {
|
|
460
|
+
args: {
|
|
461
|
+
options: basicOptions,
|
|
462
|
+
defaultText: 'Select configuration',
|
|
463
|
+
alert: {
|
|
464
|
+
type: 'info',
|
|
465
|
+
message: 'Tip: You can change this setting later in your preferences.'
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
parameters: {
|
|
469
|
+
docs: {
|
|
470
|
+
description: {
|
|
471
|
+
story: 'Info alert to provide additional context or helpful information.'
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
export const InvalidState = {
|
|
477
|
+
args: {
|
|
478
|
+
options: basicOptions,
|
|
479
|
+
defaultText: 'Invalid selection',
|
|
480
|
+
invalid: true
|
|
481
|
+
},
|
|
482
|
+
parameters: {
|
|
483
|
+
docs: {
|
|
484
|
+
description: {
|
|
485
|
+
story: 'Shows the select in an invalid state with red outline styling.'
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
export const InvalidWithAlert = {
|
|
491
|
+
args: {
|
|
492
|
+
options: basicOptions,
|
|
493
|
+
defaultText: 'Select a value',
|
|
494
|
+
invalid: true,
|
|
495
|
+
alert: {
|
|
496
|
+
type: 'error',
|
|
497
|
+
message: 'Please select a valid option to continue.'
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
parameters: {
|
|
501
|
+
docs: {
|
|
502
|
+
description: {
|
|
503
|
+
story: 'Combines invalid state styling with an error alert message for comprehensive validation feedback.'
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
export const ValidationStates = {
|
|
509
|
+
args: {
|
|
510
|
+
options: [
|
|
511
|
+
{ label: 'Option A', value: 'a' },
|
|
512
|
+
{ label: 'Option B', value: 'b' },
|
|
513
|
+
{ label: 'Option C', value: 'c' }
|
|
514
|
+
],
|
|
515
|
+
defaultText: 'Validation example'
|
|
516
|
+
},
|
|
517
|
+
parameters: {
|
|
518
|
+
docs: {
|
|
519
|
+
description: {
|
|
520
|
+
story: 'Basic validation state. See other validation stories (WithErrorAlert, WithWarningAlert, etc.) for different alert types and invalid states.'
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
// Form validation example
|
|
526
|
+
export const FormValidationExample = {
|
|
527
|
+
render: (args) => ({
|
|
528
|
+
Component: Select,
|
|
529
|
+
props: {
|
|
530
|
+
...args,
|
|
531
|
+
onchange: (event) => {
|
|
532
|
+
// Simulate form validation
|
|
533
|
+
const value = event.value;
|
|
534
|
+
if (!value) {
|
|
535
|
+
// Update to show required field error
|
|
536
|
+
console.log('Validation: Field is required');
|
|
537
|
+
}
|
|
538
|
+
else if (value === 'option3') {
|
|
539
|
+
// Show warning for specific option
|
|
540
|
+
console.log('Validation: Warning for option 3');
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
// Valid selection
|
|
544
|
+
console.log('Validation: Valid selection');
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}),
|
|
549
|
+
args: {
|
|
550
|
+
options: [
|
|
551
|
+
{ label: 'Valid Option 1', value: 'option1' },
|
|
552
|
+
{ label: 'Valid Option 2', value: 'option2' },
|
|
553
|
+
{ label: 'Problematic Option', value: 'option3' },
|
|
554
|
+
{ label: 'Another Valid Option', value: 'option4' }
|
|
555
|
+
],
|
|
556
|
+
defaultText: 'Choose wisely...',
|
|
557
|
+
alert: {
|
|
558
|
+
type: 'info',
|
|
559
|
+
message: 'Select an option to see validation feedback'
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
parameters: {
|
|
563
|
+
docs: {
|
|
564
|
+
description: {
|
|
565
|
+
story: 'Interactive example showing how validation states might change based on user selection in a real form.'
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { CheckIcon, ChevronIcon, UndoIcon } from '../../icons';
|
|
14
14
|
|
|
15
|
+
import { Tooltip } from '..';
|
|
15
16
|
import { Text } from '../text';
|
|
16
17
|
import type { DropdownInstance, SelectInstanceManager, SelectProps } from './types.js';
|
|
17
18
|
|
|
@@ -33,6 +34,8 @@
|
|
|
33
34
|
preventNoSelection = false,
|
|
34
35
|
disabled = false,
|
|
35
36
|
placement = 'bottom',
|
|
37
|
+
alert = null,
|
|
38
|
+
invalid = false,
|
|
36
39
|
className = '',
|
|
37
40
|
onchange,
|
|
38
41
|
children
|
|
@@ -85,6 +88,9 @@
|
|
|
85
88
|
}
|
|
86
89
|
});
|
|
87
90
|
|
|
91
|
+
// Computed states
|
|
92
|
+
let hasAlert = $derived(alert?.message);
|
|
93
|
+
|
|
88
94
|
// Computed styles based on state
|
|
89
95
|
const dropdownStyles = $derived(() => {
|
|
90
96
|
const base = {
|
|
@@ -101,17 +107,17 @@
|
|
|
101
107
|
};
|
|
102
108
|
}
|
|
103
109
|
|
|
104
|
-
if (hasError) {
|
|
110
|
+
if (hasError || hasAlert || invalid) {
|
|
105
111
|
return {
|
|
106
112
|
...base,
|
|
107
|
-
|
|
113
|
+
outline: '1px solid var(--redBorder)'
|
|
108
114
|
};
|
|
109
115
|
}
|
|
110
116
|
|
|
111
117
|
if (isFocused) {
|
|
112
118
|
return {
|
|
113
119
|
...base,
|
|
114
|
-
|
|
120
|
+
outline: '1px solid var(--blueBorder)'
|
|
115
121
|
};
|
|
116
122
|
}
|
|
117
123
|
|
|
@@ -393,6 +399,23 @@
|
|
|
393
399
|
debouncedFilterOptions(searchValue, options);
|
|
394
400
|
};
|
|
395
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Gets the tooltip background color based on alert type
|
|
404
|
+
*/
|
|
405
|
+
const getTooltipColor = (alertType: string) => {
|
|
406
|
+
switch (alertType) {
|
|
407
|
+
case 'error':
|
|
408
|
+
return 'var(--redBackground, #ff4d4d)';
|
|
409
|
+
case 'warning':
|
|
410
|
+
return 'var(--orangeBackground, #ff9933)';
|
|
411
|
+
case 'success':
|
|
412
|
+
return 'var(--greenBackground, #00cc66)';
|
|
413
|
+
case 'info':
|
|
414
|
+
default:
|
|
415
|
+
return 'var(--blueBackground, #4d9fff)';
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
|
|
396
419
|
// Lifecycle cleanup
|
|
397
420
|
$effect(() => {
|
|
398
421
|
return () => {
|
|
@@ -401,134 +424,159 @@
|
|
|
401
424
|
});
|
|
402
425
|
</script>
|
|
403
426
|
|
|
404
|
-
|
|
405
|
-
class="dropdown-wrapper {className}"
|
|
406
|
-
bind:this={dropdownWrapper}
|
|
407
|
-
style="{hide ? 'display:none;' : ''} width: {width};"
|
|
408
|
-
>
|
|
427
|
+
{#snippet selectWrapper()}
|
|
409
428
|
<div
|
|
410
|
-
class="dropdown"
|
|
411
|
-
|
|
412
|
-
{
|
|
413
|
-
style="width:{width}; {Object.entries(dropdownStyles())
|
|
414
|
-
.map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${value}`)
|
|
415
|
-
.join('; ')}"
|
|
416
|
-
aria-disabled={disabled}
|
|
417
|
-
tabindex={disabled || isOpen ? -1 : 0}
|
|
418
|
-
role="button"
|
|
419
|
-
aria-haspopup="listbox"
|
|
420
|
-
aria-labelledby={id}
|
|
421
|
-
bind:this={target}
|
|
422
|
-
onmouseenter={() => (isHovered = true)}
|
|
423
|
-
onmouseleave={() => (isHovered = false)}
|
|
424
|
-
onfocus={() => (isFocused = true)}
|
|
425
|
-
onblur={() => (isFocused = false)}
|
|
429
|
+
class="dropdown-wrapper {className}"
|
|
430
|
+
bind:this={dropdownWrapper}
|
|
431
|
+
style="{hide ? 'display:none;' : ''} width: {width};"
|
|
426
432
|
>
|
|
427
|
-
<div class="dropdown-header" aria-disabled={disabled}>
|
|
428
|
-
<div class="label">
|
|
429
|
-
{selected ? selectedLabel || defaultText : defaultText}
|
|
430
|
-
</div>
|
|
431
|
-
<div class="arrow" style="transform:rotate({isOpen ? '270deg' : '90deg'})">
|
|
432
|
-
<ChevronIcon />
|
|
433
|
-
</div>
|
|
434
|
-
</div>
|
|
435
|
-
|
|
436
433
|
<div
|
|
434
|
+
class="dropdown"
|
|
435
|
+
class:disabled
|
|
436
|
+
{id}
|
|
437
|
+
style="width:{width}; {Object.entries(dropdownStyles())
|
|
438
|
+
.map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${value}`)
|
|
439
|
+
.join('; ')}"
|
|
440
|
+
aria-disabled={disabled}
|
|
437
441
|
tabindex={disabled || isOpen ? -1 : 0}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
bind:this={dropdownItems}
|
|
442
|
+
role="button"
|
|
443
|
+
aria-haspopup="listbox"
|
|
444
|
+
aria-labelledby={id}
|
|
445
|
+
bind:this={target}
|
|
446
|
+
onmouseenter={() => (isHovered = true)}
|
|
447
|
+
onmouseleave={() => (isHovered = false)}
|
|
448
|
+
onfocus={() => (isFocused = true)}
|
|
449
|
+
onblur={() => (isFocused = false)}
|
|
447
450
|
>
|
|
448
|
-
{
|
|
449
|
-
<div class="
|
|
450
|
-
|
|
451
|
-
<Text label={selectedLabel} fontSize="normal" fontColor="var(--text1)" />
|
|
452
|
-
</div>
|
|
451
|
+
<div class="dropdown-header" aria-disabled={disabled}>
|
|
452
|
+
<div class="label">
|
|
453
|
+
{selected ? selectedLabel || defaultText : defaultText}
|
|
453
454
|
</div>
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
455
|
+
<div class="arrow" style="transform:rotate({isOpen ? '270deg' : '90deg'})">
|
|
456
|
+
<ChevronIcon />
|
|
457
|
+
</div>
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
<div
|
|
461
|
+
tabindex={disabled || isOpen ? -1 : 0}
|
|
462
|
+
class="dropdown-list"
|
|
463
|
+
role="listbox"
|
|
464
|
+
style="width:{dropdownWidth}; max-height:{dropdownHeight};"
|
|
465
|
+
onkeydown={(e) => {
|
|
466
|
+
e.stopPropagation();
|
|
467
|
+
e.preventDefault();
|
|
468
|
+
handleKeyDown(e);
|
|
469
|
+
}}
|
|
470
|
+
bind:this={dropdownItems}
|
|
471
|
+
>
|
|
472
|
+
{#if selectedLabel}
|
|
473
|
+
<div class="selected">
|
|
474
|
+
<div class="label">
|
|
475
|
+
<Text label={selectedLabel} fontSize="normal" fontColor="var(--text1)" />
|
|
476
|
+
</div>
|
|
477
|
+
</div>
|
|
478
|
+
{/if}
|
|
479
|
+
|
|
480
|
+
{#if enableSearch}
|
|
481
|
+
<div class="search-container">
|
|
482
|
+
<input
|
|
483
|
+
type="text"
|
|
484
|
+
placeholder="Search"
|
|
485
|
+
oninput={(e) => {
|
|
486
|
+
e.stopPropagation();
|
|
487
|
+
e.preventDefault();
|
|
488
|
+
handleSearch(e);
|
|
489
|
+
}}
|
|
490
|
+
onkeydown={(e) => e.stopPropagation()}
|
|
491
|
+
/>
|
|
492
|
+
</div>
|
|
493
|
+
{/if}
|
|
494
|
+
|
|
495
|
+
{#each optionsStore?.length > 0 ? optionsStore : options as { label, value, className = null, description = null, labelIcon = null, descriptionTitle = null, isDisabled = false }, index (index)}
|
|
496
|
+
{@const indexId = index + 1}
|
|
497
|
+
{@const itemId = ref ? ref.replace(' ', '-') : 'dropdown'}
|
|
498
|
+
<button
|
|
499
|
+
aria-posinset={indexId}
|
|
500
|
+
aria-selected={value === selected && selected?.trim() !== '' ? 'true' : 'false'}
|
|
501
|
+
id={`${itemId}-list-${indexId}-${id}`}
|
|
502
|
+
data-value={value}
|
|
503
|
+
class="dropdown-item {isDisabled ? 'disabled' : ''} {className}"
|
|
504
|
+
role="option"
|
|
505
|
+
onclick={(e) => {
|
|
506
|
+
e.stopPropagation();
|
|
507
|
+
if (isDisabled) return;
|
|
508
|
+
handleSelect(value, label, e.currentTarget);
|
|
509
|
+
}}
|
|
510
|
+
onkeydown={(e) => {
|
|
462
511
|
e.stopPropagation();
|
|
463
512
|
e.preventDefault();
|
|
464
|
-
handleSearch(e);
|
|
465
513
|
}}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
{#if value === selected && selected?.trim() !== ''}
|
|
497
|
-
<CheckIcon />
|
|
498
|
-
{/if}
|
|
499
|
-
</div>
|
|
500
|
-
<div class="label">
|
|
501
|
-
{#if description || descriptionTitle || labelIcon}
|
|
502
|
-
<div class="label-content">
|
|
503
|
-
<div class="label-name">
|
|
504
|
-
<Text {label} />
|
|
505
|
-
{#if labelIcon}
|
|
506
|
-
{@const IconComponent = labelIcon}
|
|
507
|
-
<IconComponent />
|
|
508
|
-
{/if}
|
|
509
|
-
</div>
|
|
510
|
-
<div class="label-description-title">
|
|
511
|
-
<Text
|
|
512
|
-
label={descriptionTitle || ''}
|
|
513
|
-
fontColor="var(--greenText)"
|
|
514
|
-
fontSize="10px"
|
|
515
|
-
/>
|
|
514
|
+
onmouseenter={handleMouseEnter}
|
|
515
|
+
aria-hidden={!isOpen}
|
|
516
|
+
tabindex={value === selected ? 0 : -1}
|
|
517
|
+
style={description ? 'align-items:start;' : ''}
|
|
518
|
+
>
|
|
519
|
+
<div class="icon" aria-label={label}>
|
|
520
|
+
{#if value === selected && selected?.trim() !== ''}
|
|
521
|
+
<CheckIcon />
|
|
522
|
+
{/if}
|
|
523
|
+
</div>
|
|
524
|
+
<div class="label">
|
|
525
|
+
{#if description || descriptionTitle || labelIcon}
|
|
526
|
+
<div class="label-content">
|
|
527
|
+
<div class="label-name">
|
|
528
|
+
<Text {label} />
|
|
529
|
+
{#if labelIcon}
|
|
530
|
+
{@const IconComponent = labelIcon}
|
|
531
|
+
<IconComponent />
|
|
532
|
+
{/if}
|
|
533
|
+
</div>
|
|
534
|
+
<div class="label-description-title">
|
|
535
|
+
<Text
|
|
536
|
+
label={descriptionTitle || ''}
|
|
537
|
+
fontColor="var(--greenText)"
|
|
538
|
+
fontSize="10px"
|
|
539
|
+
/>
|
|
540
|
+
</div>
|
|
541
|
+
<div class="label-description">
|
|
542
|
+
<Text label={description || ''} fontColor="var(--text2)" fontSize="10px" />
|
|
543
|
+
</div>
|
|
516
544
|
</div>
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
</div>
|
|
525
|
-
</button>
|
|
526
|
-
{/each}
|
|
545
|
+
{:else}
|
|
546
|
+
<Text {label} fontSize="normal" />
|
|
547
|
+
{/if}
|
|
548
|
+
</div>
|
|
549
|
+
</button>
|
|
550
|
+
{/each}
|
|
551
|
+
</div>
|
|
527
552
|
</div>
|
|
528
553
|
</div>
|
|
529
|
-
|
|
554
|
+
{/snippet}
|
|
555
|
+
|
|
556
|
+
<Tooltip
|
|
557
|
+
message={hasAlert ? alert?.message || '' : ''}
|
|
558
|
+
placement="top"
|
|
559
|
+
listener="hover"
|
|
560
|
+
listenerout="hover"
|
|
561
|
+
showArrow={true}
|
|
562
|
+
hidden={!hasAlert}
|
|
563
|
+
disabled={!hasAlert || !alert?.message}
|
|
564
|
+
fontColor="var(--actionPrimaryText)"
|
|
565
|
+
width="max-content"
|
|
566
|
+
padding="6px"
|
|
567
|
+
bgColor={getTooltipColor(alert?.type || 'info')}
|
|
568
|
+
class="select-tooltip"
|
|
569
|
+
>
|
|
570
|
+
{#snippet target()}
|
|
571
|
+
{@render selectWrapper()}
|
|
572
|
+
{/snippet}
|
|
573
|
+
</Tooltip>
|
|
530
574
|
|
|
531
575
|
<style>
|
|
576
|
+
:global(.select-tooltip) {
|
|
577
|
+
padding: 0;
|
|
578
|
+
}
|
|
579
|
+
|
|
532
580
|
.dropdown-item.disabled {
|
|
533
581
|
opacity: 0.75;
|
|
534
582
|
cursor: not-allowed;
|
|
@@ -619,7 +667,7 @@
|
|
|
619
667
|
}
|
|
620
668
|
|
|
621
669
|
.dropdown-list :global(.dropdown-item.hover-state) {
|
|
622
|
-
|
|
670
|
+
outline: 1px solid var(--blueBorder);
|
|
623
671
|
}
|
|
624
672
|
|
|
625
673
|
.dropdown-list {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { Placement } from '@floating-ui/dom';
|
|
2
2
|
import type { Component, Snippet } from 'svelte';
|
|
3
|
+
export type AlertType = 'error' | 'success' | 'info' | 'warning';
|
|
4
|
+
export interface AlertConfig {
|
|
5
|
+
type: AlertType;
|
|
6
|
+
message: string;
|
|
7
|
+
}
|
|
3
8
|
export type SelectValue = string & {
|
|
4
9
|
readonly brand: unique symbol;
|
|
5
10
|
};
|
|
@@ -37,6 +42,14 @@ export interface SelectProps {
|
|
|
37
42
|
preventNoSelection?: boolean;
|
|
38
43
|
disabled?: boolean;
|
|
39
44
|
placement?: Placement;
|
|
45
|
+
/**
|
|
46
|
+
* Alert configuration for showing validation messages
|
|
47
|
+
*/
|
|
48
|
+
alert?: AlertConfig | null;
|
|
49
|
+
/**
|
|
50
|
+
* If true, the select will be invalid
|
|
51
|
+
*/
|
|
52
|
+
invalid?: boolean;
|
|
40
53
|
className?: string;
|
|
41
54
|
onchange?: SelectChangeHandler;
|
|
42
55
|
children?: Snippet;
|
|
@@ -345,11 +345,11 @@
|
|
|
345
345
|
{#if tooltip}
|
|
346
346
|
{@render tooltip()}
|
|
347
347
|
{:else if message && raw}
|
|
348
|
-
<div class="message" style="color:{fontColor};">
|
|
348
|
+
<div class="message" style="color:{fontColor}; background-color: {bgColor};">
|
|
349
349
|
{@html message}
|
|
350
350
|
</div>
|
|
351
351
|
{:else if message}
|
|
352
|
-
<div class="message">
|
|
352
|
+
<div class="message" style="color:{fontColor}; background-color: {bgColor};">
|
|
353
353
|
<Text label={formattedMessage} fontSize="11px" fontWeight="500" {fontColor} />
|
|
354
354
|
</div>
|
|
355
355
|
{/if}
|
|
@@ -15,8 +15,8 @@ export declare const getPathname: (page: Page | Folder) => Promise<string>;
|
|
|
15
15
|
/**
|
|
16
16
|
* Returns a single page with all its properties.
|
|
17
17
|
*/
|
|
18
|
-
export declare const getPageMetadata: (page: Page) => Promise<PageWithProps>;
|
|
18
|
+
export declare const getPageMetadata: (page: Page, targetUrl?: URL) => Promise<PageWithProps>;
|
|
19
19
|
/**
|
|
20
20
|
* Returns all pages and folders from the Webflow project.
|
|
21
21
|
*/
|
|
22
|
-
export declare const getAllPages: (pagesAndFolders?: boolean, kind?: PageWithProps["kind"]) => Promise<PageWithProps[]>;
|
|
22
|
+
export declare const getAllPages: (pagesAndFolders?: boolean, kind?: PageWithProps["kind"], targetUrl?: URL) => Promise<PageWithProps[]>;
|
|
@@ -18,10 +18,11 @@ export const getPathname = async (page) => {
|
|
|
18
18
|
/**
|
|
19
19
|
* Returns a single page with all its properties.
|
|
20
20
|
*/
|
|
21
|
-
export const getPageMetadata = async (page) => {
|
|
21
|
+
export const getPageMetadata = async (page, targetUrl) => {
|
|
22
22
|
if (!pageStagingUrl) {
|
|
23
|
-
const {
|
|
24
|
-
|
|
23
|
+
const { domains } = await webflow.getSiteInfo();
|
|
24
|
+
const stagingUrl = domains.find((domain) => domain.stage === 'staging')?.url;
|
|
25
|
+
pageStagingUrl = targetUrl?.toString() || `https://${stagingUrl}`;
|
|
25
26
|
}
|
|
26
27
|
const [fullPath, parent, name, kind, isDraft, isPasswordProtected, generatedPathname] = await Promise.all([
|
|
27
28
|
page?.getPublishPath(),
|
|
@@ -50,7 +51,7 @@ export const getPageMetadata = async (page) => {
|
|
|
50
51
|
/**
|
|
51
52
|
* Returns all pages and folders from the Webflow project.
|
|
52
53
|
*/
|
|
53
|
-
export const getAllPages = async (pagesAndFolders, kind) => {
|
|
54
|
+
export const getAllPages = async (pagesAndFolders, kind, targetUrl) => {
|
|
54
55
|
try {
|
|
55
56
|
const allPages = await webflow?.getAllPagesAndFolders();
|
|
56
57
|
const pagesWithPropsPromises = [];
|
|
@@ -58,7 +59,7 @@ export const getAllPages = async (pagesAndFolders, kind) => {
|
|
|
58
59
|
for (const page of allPages) {
|
|
59
60
|
if (page.type === 'PageFolder')
|
|
60
61
|
continue;
|
|
61
|
-
pagesWithPropsPromises.push(getPageMetadata(page));
|
|
62
|
+
pagesWithPropsPromises.push(getPageMetadata(page, targetUrl));
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
const list = await Promise.all(pagesWithPropsPromises);
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
* Returns a valid Webflow project staging URL.
|
|
3
3
|
*/
|
|
4
4
|
export const getSiteStagingUrl = async (origin, stagingName) => {
|
|
5
|
-
const { shortName } = await webflow.getSiteInfo();
|
|
5
|
+
const { shortName, domains } = await webflow.getSiteInfo();
|
|
6
6
|
if (stagingName)
|
|
7
7
|
return shortName;
|
|
8
|
+
const stagingUrl = domains.find((domain) => domain.stage === 'staging')?.url;
|
|
8
9
|
if (origin)
|
|
9
|
-
return `${shortName}.webflow.io`;
|
|
10
|
+
return stagingUrl || `${shortName}.webflow.io`;
|
|
11
|
+
if (stagingUrl)
|
|
12
|
+
return `https://${stagingUrl}`;
|
|
10
13
|
return `https://${shortName}.webflow.io`;
|
|
11
14
|
};
|