@insymetri/styleguide 0.1.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/IIActionGroup/IIActionGroup.svelte +11 -0
- package/dist/IIActionGroup/IIActionGroup.svelte.d.ts +6 -0
- package/dist/IIActionGroup/index.d.ts +1 -0
- package/dist/IIActionGroup/index.js +1 -0
- package/dist/IIAsyncState/IIAsyncState.svelte +50 -0
- package/dist/IIAsyncState/IIAsyncState.svelte.d.ts +15 -0
- package/dist/IIAsyncState/index.d.ts +1 -0
- package/dist/IIAsyncState/index.js +1 -0
- package/dist/IIAuditTrail/IIAuditTrail.svelte +167 -0
- package/dist/IIAuditTrail/IIAuditTrail.svelte.d.ts +13 -0
- package/dist/IIAuditTrail/IIAuditTrail.types.d.ts +14 -0
- package/dist/IIAuditTrail/IIAuditTrail.types.js +1 -0
- package/dist/IIAuditTrail/index.d.ts +2 -0
- package/dist/IIAuditTrail/index.js +1 -0
- package/dist/IIBadge/IIBadge.svelte +46 -0
- package/dist/IIBadge/IIBadge.svelte.d.ts +11 -0
- package/dist/IIBadge/IIBadge.types.d.ts +1 -0
- package/dist/IIBadge/IIBadge.types.js +1 -0
- package/dist/IIBadge/index.d.ts +2 -0
- package/dist/IIBadge/index.js +1 -0
- package/dist/IIButton/IIButton.svelte +103 -0
- package/dist/IIButton/IIButton.svelte.d.ts +23 -0
- package/dist/IIButton/index.d.ts +1 -0
- package/dist/IIButton/index.js +1 -0
- package/dist/IICheckbox/IICheckbox.svelte +66 -0
- package/dist/IICheckbox/IICheckbox.svelte.d.ts +16 -0
- package/dist/IICheckbox/index.d.ts +1 -0
- package/dist/IICheckbox/index.js +1 -0
- package/dist/IICheckboxList/IICheckboxList.svelte +15 -0
- package/dist/IICheckboxList/IICheckboxList.svelte.d.ts +7 -0
- package/dist/IICheckboxList/index.d.ts +1 -0
- package/dist/IICheckboxList/index.js +1 -0
- package/dist/IICombobox/IICombobox.svelte +158 -0
- package/dist/IICombobox/IICombobox.svelte.d.ts +39 -0
- package/dist/IICombobox/index.d.ts +1 -0
- package/dist/IICombobox/index.js +1 -0
- package/dist/IIDatePicker/IIDatePicker.svelte +107 -0
- package/dist/IIDatePicker/IIDatePicker.svelte.d.ts +9 -0
- package/dist/IIDatePicker/index.d.ts +1 -0
- package/dist/IIDatePicker/index.js +1 -0
- package/dist/IIDropdownInput/IIDropdownInput.svelte +76 -0
- package/dist/IIDropdownInput/IIDropdownInput.svelte.d.ts +15 -0
- package/dist/IIDropdownInput/index.d.ts +1 -0
- package/dist/IIDropdownInput/index.js +1 -0
- package/dist/IIDropdownMenu/IIDropdownMenu.svelte +74 -0
- package/dist/IIDropdownMenu/IIDropdownMenu.svelte.d.ts +19 -0
- package/dist/IIDropdownMenu/index.d.ts +1 -0
- package/dist/IIDropdownMenu/index.js +1 -0
- package/dist/IIEditableBadges/IIEditableBadges.svelte +91 -0
- package/dist/IIEditableBadges/IIEditableBadges.svelte.d.ts +17 -0
- package/dist/IIEditableBadges/index.d.ts +1 -0
- package/dist/IIEditableBadges/index.js +1 -0
- package/dist/IIEditableText/IIEditableText.svelte +143 -0
- package/dist/IIEditableText/IIEditableText.svelte.d.ts +12 -0
- package/dist/IIEditableText/index.d.ts +1 -0
- package/dist/IIEditableText/index.js +1 -0
- package/dist/IIEmptyState/IIEmptyState.svelte +29 -0
- package/dist/IIEmptyState/IIEmptyState.svelte.d.ts +9 -0
- package/dist/IIEmptyState/index.d.ts +1 -0
- package/dist/IIEmptyState/index.js +1 -0
- package/dist/IIFilterChip/IIFilterChip.svelte +47 -0
- package/dist/IIFilterChip/IIFilterChip.svelte.d.ts +9 -0
- package/dist/IIFilterChip/index.d.ts +1 -0
- package/dist/IIFilterChip/index.js +1 -0
- package/dist/IIFormField/IIFormField.svelte +18 -0
- package/dist/IIFormField/IIFormField.svelte.d.ts +9 -0
- package/dist/IIFormField/index.d.ts +1 -0
- package/dist/IIFormField/index.js +1 -0
- package/dist/IIInput/IIInput.svelte +69 -0
- package/dist/IIInput/IIInput.svelte.d.ts +15 -0
- package/dist/IIInput/index.d.ts +1 -0
- package/dist/IIInput/index.js +1 -0
- package/dist/IIModal/IIModal.svelte +76 -0
- package/dist/IIModal/IIModal.svelte.d.ts +15 -0
- package/dist/IIModal/index.d.ts +1 -0
- package/dist/IIModal/index.js +1 -0
- package/dist/IIOverflowActions/IIOverflowActions.svelte +104 -0
- package/dist/IIOverflowActions/IIOverflowActions.svelte.d.ts +16 -0
- package/dist/IIOverflowActions/index.d.ts +1 -0
- package/dist/IIOverflowActions/index.js +1 -0
- package/dist/IIStatusBadge/IIStatusBadge.svelte +29 -0
- package/dist/IIStatusBadge/IIStatusBadge.svelte.d.ts +9 -0
- package/dist/IIStatusBadge/index.d.ts +1 -0
- package/dist/IIStatusBadge/index.js +1 -0
- package/dist/IISwitch/IISwitch.svelte +60 -0
- package/dist/IISwitch/IISwitch.svelte.d.ts +15 -0
- package/dist/IISwitch/index.d.ts +1 -0
- package/dist/IISwitch/index.js +1 -0
- package/dist/IITable/IITable.svelte +17 -0
- package/dist/IITable/IITable.svelte.d.ts +8 -0
- package/dist/IITable/index.d.ts +1 -0
- package/dist/IITable/index.js +1 -0
- package/dist/IITableSkeleton/IITableSkeleton.svelte +32 -0
- package/dist/IITableSkeleton/IITableSkeleton.svelte.d.ts +8 -0
- package/dist/IITableSkeleton/index.d.ts +1 -0
- package/dist/IITableSkeleton/index.js +1 -0
- package/dist/IITabs/IITabs.svelte +139 -0
- package/dist/IITabs/IITabs.svelte.d.ts +19 -0
- package/dist/IITabs/index.d.ts +1 -0
- package/dist/IITabs/index.js +1 -0
- package/dist/IITaskCardSkeleton/IITaskCardSkeleton.svelte +15 -0
- package/dist/IITaskCardSkeleton/IITaskCardSkeleton.svelte.d.ts +26 -0
- package/dist/IITaskCardSkeleton/index.d.ts +1 -0
- package/dist/IITaskCardSkeleton/index.js +1 -0
- package/dist/IITextarea/IITextarea.svelte +79 -0
- package/dist/IITextarea/IITextarea.svelte.d.ts +15 -0
- package/dist/IITextarea/index.d.ts +1 -0
- package/dist/IITextarea/index.js +1 -0
- package/dist/IIToaster/IIToaster.svelte +5 -0
- package/dist/IIToaster/IIToaster.svelte.d.ts +18 -0
- package/dist/IIToaster/index.d.ts +1 -0
- package/dist/IIToaster/index.js +1 -0
- package/dist/IIViewFilterChip/IIViewFilterChip.svelte +37 -0
- package/dist/IIViewFilterChip/IIViewFilterChip.svelte.d.ts +8 -0
- package/dist/IIViewFilterChip/index.d.ts +1 -0
- package/dist/IIViewFilterChip/index.js +1 -0
- package/dist/Typography/Typography.svelte +67 -0
- package/dist/Typography/Typography.svelte.d.ts +18 -0
- package/dist/Typography/index.d.ts +1 -0
- package/dist/Typography/index.js +1 -0
- package/dist/icons.d.ts +92 -0
- package/dist/icons.js +104 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +35 -0
- package/dist/style/base.css +71 -0
- package/dist/style/colors.css +183 -0
- package/dist/style/global.css +2 -0
- package/dist/style/index.d.ts +1 -0
- package/dist/style/index.js +1 -0
- package/dist/style/tailwind/animations.js +89 -0
- package/dist/style/tailwind/colors.d.ts +217 -0
- package/dist/style/tailwind/colors.js +239 -0
- package/dist/style/tailwind/preset.js +103 -0
- package/dist/style/tailwind/radius.d.ts +1 -0
- package/dist/style/tailwind/radius.js +5 -0
- package/dist/style/tailwind/shadows.d.ts +15 -0
- package/dist/style/tailwind/shadows.js +27 -0
- package/dist/style/tailwind/spacing.d.ts +1 -0
- package/dist/style/tailwind/spacing.js +37 -0
- package/dist/style/tailwind/typography.d.ts +100 -0
- package/dist/style/tailwind/typography.js +39 -0
- package/dist/style/tailwind/z-index.d.ts +1 -0
- package/dist/style/tailwind/z-index.js +7 -0
- package/dist/toast.d.ts +16 -0
- package/dist/toast.js +24 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/cn.js +4 -0
- package/package.json +79 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {cn} from '../utils/cn'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
value: string
|
|
6
|
+
displayValue?: string
|
|
7
|
+
onSave: (newValue: string) => Promise<void>
|
|
8
|
+
multiline?: boolean
|
|
9
|
+
placeholder?: string
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
maxLength?: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {value, displayValue, onSave, multiline = false, placeholder = '', disabled = false, maxLength}: Props = $props()
|
|
15
|
+
|
|
16
|
+
let isEditing = $state(false)
|
|
17
|
+
let isSaving = $state(false)
|
|
18
|
+
let editValue = $state(value)
|
|
19
|
+
let inputElement = $state<HTMLInputElement | HTMLTextAreaElement | null>(null)
|
|
20
|
+
let hasError = $state(false)
|
|
21
|
+
|
|
22
|
+
function startEditing() {
|
|
23
|
+
if (disabled || isSaving) return
|
|
24
|
+
editValue = value
|
|
25
|
+
isEditing = true
|
|
26
|
+
hasError = false
|
|
27
|
+
// Focus after DOM updates
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
inputElement?.focus()
|
|
30
|
+
inputElement?.select()
|
|
31
|
+
}, 0)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function cancelEditing() {
|
|
35
|
+
isEditing = false
|
|
36
|
+
editValue = value
|
|
37
|
+
hasError = false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function saveEditing() {
|
|
41
|
+
const trimmedValue = editValue.trim()
|
|
42
|
+
|
|
43
|
+
// Don't save if unchanged or empty
|
|
44
|
+
if (trimmedValue === value) {
|
|
45
|
+
cancelEditing()
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!trimmedValue) {
|
|
50
|
+
hasError = true
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
isSaving = true
|
|
56
|
+
hasError = false
|
|
57
|
+
await onSave(trimmedValue)
|
|
58
|
+
isEditing = false
|
|
59
|
+
} catch {
|
|
60
|
+
hasError = true
|
|
61
|
+
} finally {
|
|
62
|
+
isSaving = false
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
67
|
+
if (e.key === 'Escape') {
|
|
68
|
+
e.preventDefault()
|
|
69
|
+
cancelEditing()
|
|
70
|
+
} else if (e.key === 'Enter' && !multiline) {
|
|
71
|
+
e.preventDefault()
|
|
72
|
+
saveEditing()
|
|
73
|
+
} else if (e.key === 'Enter' && multiline && (e.metaKey || e.ctrlKey)) {
|
|
74
|
+
e.preventDefault()
|
|
75
|
+
saveEditing()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function handleBlur() {
|
|
80
|
+
// Small delay to allow click events to process first
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
if (isEditing && !isSaving) {
|
|
83
|
+
saveEditing()
|
|
84
|
+
}
|
|
85
|
+
}, 150)
|
|
86
|
+
}
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
{#if isEditing}
|
|
90
|
+
<div class="relative w-full">
|
|
91
|
+
{#if multiline}
|
|
92
|
+
<textarea
|
|
93
|
+
bind:this={inputElement}
|
|
94
|
+
bind:value={editValue}
|
|
95
|
+
onkeydown={handleKeydown}
|
|
96
|
+
onblur={handleBlur}
|
|
97
|
+
disabled={isSaving}
|
|
98
|
+
{placeholder}
|
|
99
|
+
maxlength={maxLength}
|
|
100
|
+
class={cn(
|
|
101
|
+
'w-full p-8 border border-primary rounded-4 text-small font-inherit text-body bg-background transition-all duration-fast focus:outline-none focus:border-primary resize-y min-h-60',
|
|
102
|
+
hasError && 'border-error',
|
|
103
|
+
isSaving && 'opacity-70 cursor-wait'
|
|
104
|
+
)}
|
|
105
|
+
rows={3}
|
|
106
|
+
></textarea>
|
|
107
|
+
{:else}
|
|
108
|
+
<input
|
|
109
|
+
type="text"
|
|
110
|
+
bind:this={inputElement}
|
|
111
|
+
bind:value={editValue}
|
|
112
|
+
onkeydown={handleKeydown}
|
|
113
|
+
onblur={handleBlur}
|
|
114
|
+
disabled={isSaving}
|
|
115
|
+
{placeholder}
|
|
116
|
+
maxlength={maxLength}
|
|
117
|
+
class={cn(
|
|
118
|
+
'w-full p-8 border border-primary rounded-4 text-small font-inherit text-body bg-background transition-all duration-fast focus:outline-none focus:border-primary',
|
|
119
|
+
hasError && 'border-error',
|
|
120
|
+
isSaving && 'opacity-70 cursor-wait'
|
|
121
|
+
)}
|
|
122
|
+
/>
|
|
123
|
+
{/if}
|
|
124
|
+
{#if hasError}
|
|
125
|
+
<span class="block mt-4 text-tiny text-error">Value cannot be empty</span>
|
|
126
|
+
{/if}
|
|
127
|
+
{#if isSaving}
|
|
128
|
+
<span class="block mt-4 text-tiny text-secondary italic">Saving...</span>
|
|
129
|
+
{/if}
|
|
130
|
+
</div>
|
|
131
|
+
{:else}
|
|
132
|
+
<button
|
|
133
|
+
type="button"
|
|
134
|
+
class={cn(
|
|
135
|
+
'[all:unset] cursor-text block w-full py-4 border-b-2 border-transparent transition-all duration-fast text-left hover:border-b-primary focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2 focus-visible:rounded-4',
|
|
136
|
+
disabled && 'cursor-not-allowed opacity-60'
|
|
137
|
+
)}
|
|
138
|
+
onclick={startEditing}
|
|
139
|
+
{disabled}
|
|
140
|
+
>
|
|
141
|
+
{displayValue || value || placeholder}
|
|
142
|
+
</button>
|
|
143
|
+
{/if}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type Props = {
|
|
2
|
+
value: string;
|
|
3
|
+
displayValue?: string;
|
|
4
|
+
onSave: (newValue: string) => Promise<void>;
|
|
5
|
+
multiline?: boolean;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
maxLength?: number;
|
|
9
|
+
};
|
|
10
|
+
declare const IIEditableText: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type IIEditableText = ReturnType<typeof IIEditableText>;
|
|
12
|
+
export default IIEditableText;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIEditableText } from './IIEditableText.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIEditableText } from './IIEditableText.svelte';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {Snippet} from 'svelte'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
icon?: Snippet
|
|
6
|
+
title: string
|
|
7
|
+
subtitle?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let {icon, title, subtitle}: Props = $props()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
{#if icon}
|
|
14
|
+
<div class="p-32 text-center">
|
|
15
|
+
<div class="flex flex-col items-center gap-12">
|
|
16
|
+
<div class="w-12 h-12 text-tertiary opacity-50 flex items-center justify-center">
|
|
17
|
+
{@render icon()}
|
|
18
|
+
</div>
|
|
19
|
+
<p class="text-small-emphasis text-secondary m-0">{title}</p>
|
|
20
|
+
{#if subtitle}
|
|
21
|
+
<p class="text-tiny text-tertiary m-0">{subtitle}</p>
|
|
22
|
+
{/if}
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
{:else}
|
|
26
|
+
<div class="p-32 text-center text-secondary text-small">
|
|
27
|
+
{title}
|
|
28
|
+
</div>
|
|
29
|
+
{/if}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Props = {
|
|
3
|
+
icon?: Snippet;
|
|
4
|
+
title: string;
|
|
5
|
+
subtitle?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const IIEmptyState: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type IIEmptyState = ReturnType<typeof IIEmptyState>;
|
|
9
|
+
export default IIEmptyState;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIEmptyState } from './IIEmptyState.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIEmptyState } from './IIEmptyState.svelte';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {IconClose} from '../icons'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
fieldLabel: string
|
|
6
|
+
operator: string
|
|
7
|
+
value: string
|
|
8
|
+
onRemove: () => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let {fieldLabel, operator, value, onRemove}: Props = $props()
|
|
12
|
+
|
|
13
|
+
const operatorDisplay = $derived.by(() => {
|
|
14
|
+
const map: Record<string, string> = {
|
|
15
|
+
'=': 'is',
|
|
16
|
+
'!=': 'is not',
|
|
17
|
+
'<': '<',
|
|
18
|
+
'>': '>',
|
|
19
|
+
'<=': '<=',
|
|
20
|
+
'>=': '>=',
|
|
21
|
+
IN: 'in',
|
|
22
|
+
'NOT IN': 'not in',
|
|
23
|
+
IS: 'is',
|
|
24
|
+
'IS NOT': 'is not',
|
|
25
|
+
IS_EMPTY: 'is empty',
|
|
26
|
+
IS_NOT_EMPTY: 'is not empty',
|
|
27
|
+
}
|
|
28
|
+
return map[operator] || operator
|
|
29
|
+
})
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<span
|
|
33
|
+
class="inline-flex items-center gap-4 px-8 py-4 bg-filter-bg border border-filter-border rounded-full text-tiny text-filter-text"
|
|
34
|
+
>
|
|
35
|
+
<span class="flex items-center gap-4">
|
|
36
|
+
<span class="font-medium">{fieldLabel}</span>
|
|
37
|
+
<span class="text-filter-operator">{operatorDisplay}</span>
|
|
38
|
+
<span class="font-semibold">{value || 'NULL'}</span>
|
|
39
|
+
</span>
|
|
40
|
+
<button
|
|
41
|
+
class="flex items-center justify-center w-16 h-16 p-0 bg-filter-remove border-0 rounded-full cursor-default transition-all duration-fast hover:bg-filter-remove-hover [&_svg]:w-10 [&_svg]:h-10 [&_svg]:text-filter-remove-icon"
|
|
42
|
+
onclick={onRemove}
|
|
43
|
+
aria-label="Remove filter"
|
|
44
|
+
>
|
|
45
|
+
<IconClose />
|
|
46
|
+
</button>
|
|
47
|
+
</span>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIFilterChip } from './IIFilterChip.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIFilterChip } from './IIFilterChip.svelte';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {Snippet} from 'svelte'
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
label?: string
|
|
6
|
+
id?: string
|
|
7
|
+
children: Snippet
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let {label, id, children}: Props = $props()
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="mb-16 last:mb-0">
|
|
14
|
+
{#if label}
|
|
15
|
+
<label class="block text-small-emphasis text-body mb-8" for={id}>{label}</label>
|
|
16
|
+
{/if}
|
|
17
|
+
{@render children()}
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Props = {
|
|
3
|
+
label?: string;
|
|
4
|
+
id?: string;
|
|
5
|
+
children: Snippet;
|
|
6
|
+
};
|
|
7
|
+
declare const IIFormField: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type IIFormField = ReturnType<typeof IIFormField>;
|
|
9
|
+
export default IIFormField;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIFormField } from './IIFormField.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIFormField } from './IIFormField.svelte';
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {HTMLInputAttributes} from 'svelte/elements'
|
|
3
|
+
import {cn} from '../utils/cn'
|
|
4
|
+
|
|
5
|
+
type Props = HTMLInputAttributes & {
|
|
6
|
+
label?: string
|
|
7
|
+
errorMessage?: string
|
|
8
|
+
helperText?: string
|
|
9
|
+
error?: boolean
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search'
|
|
12
|
+
value?: string | number
|
|
13
|
+
ref?: HTMLInputElement
|
|
14
|
+
class?: string
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let {
|
|
18
|
+
label,
|
|
19
|
+
errorMessage,
|
|
20
|
+
helperText,
|
|
21
|
+
error = false,
|
|
22
|
+
disabled = false,
|
|
23
|
+
type = 'text',
|
|
24
|
+
value = $bindable(),
|
|
25
|
+
ref = $bindable(),
|
|
26
|
+
class: className,
|
|
27
|
+
...restProps
|
|
28
|
+
}: Props = $props()
|
|
29
|
+
|
|
30
|
+
const showError = $derived(error || !!errorMessage)
|
|
31
|
+
let shouldShake = $state(false)
|
|
32
|
+
let prevShowError = $state(false)
|
|
33
|
+
|
|
34
|
+
$effect(() => {
|
|
35
|
+
if (showError && !prevShowError) {
|
|
36
|
+
shouldShake = true
|
|
37
|
+
const timer = setTimeout(() => {
|
|
38
|
+
shouldShake = false
|
|
39
|
+
}, 400)
|
|
40
|
+
return () => clearTimeout(timer)
|
|
41
|
+
}
|
|
42
|
+
prevShowError = showError
|
|
43
|
+
})
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<div class={cn('flex flex-col gap-4', className)}>
|
|
47
|
+
{#if label}
|
|
48
|
+
<label for={restProps.id} class="text-small-emphasis text-body">
|
|
49
|
+
{label}
|
|
50
|
+
</label>
|
|
51
|
+
{/if}
|
|
52
|
+
<input
|
|
53
|
+
bind:this={ref}
|
|
54
|
+
bind:value
|
|
55
|
+
{type}
|
|
56
|
+
{disabled}
|
|
57
|
+
class={cn(
|
|
58
|
+
'py-6 px-12 text-small font-[family-name:var(--font-family)] text-input-text bg-input-bg border border-input-border rounded-10 transition-all duration-fast outline-none w-full box-border placeholder:text-input-placeholder hover:border-input-border-hover focus:border-input-border-hover disabled:bg-input-bg-disabled disabled:text-input-text-disabled disabled:cursor-not-allowed motion-reduce:transition-none motion-reduce:animate-none',
|
|
59
|
+
showError && 'border-input-border-error focus:border-input-border-error focus:ring-error',
|
|
60
|
+
shouldShake && 'animate-shake'
|
|
61
|
+
)}
|
|
62
|
+
{...restProps}
|
|
63
|
+
/>
|
|
64
|
+
{#if showError && errorMessage}
|
|
65
|
+
<span class="text-tiny text-error">{errorMessage}</span>
|
|
66
|
+
{:else if helperText}
|
|
67
|
+
<span class="text-tiny text-secondary">{helperText}</span>
|
|
68
|
+
{/if}
|
|
69
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
2
|
+
type Props = HTMLInputAttributes & {
|
|
3
|
+
label?: string;
|
|
4
|
+
errorMessage?: string;
|
|
5
|
+
helperText?: string;
|
|
6
|
+
error?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search';
|
|
9
|
+
value?: string | number;
|
|
10
|
+
ref?: HTMLInputElement;
|
|
11
|
+
class?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const IIInput: import("svelte").Component<Props, {}, "value" | "ref">;
|
|
14
|
+
type IIInput = ReturnType<typeof IIInput>;
|
|
15
|
+
export default IIInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIInput } from './IIInput.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIInput } from './IIInput.svelte';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {Snippet} from 'svelte'
|
|
3
|
+
import {Dialog} from 'bits-ui'
|
|
4
|
+
import {IconClose} from '../icons'
|
|
5
|
+
import {cn} from '../utils/cn'
|
|
6
|
+
|
|
7
|
+
type Props = {
|
|
8
|
+
open: boolean
|
|
9
|
+
title: string
|
|
10
|
+
onOpenChange?: (open: boolean) => void
|
|
11
|
+
children: Snippet
|
|
12
|
+
description?: Snippet
|
|
13
|
+
footer?: Snippet
|
|
14
|
+
showCloseButton?: boolean
|
|
15
|
+
size?: 'sm' | 'md' | 'lg'
|
|
16
|
+
class?: string
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let {
|
|
20
|
+
open = $bindable(),
|
|
21
|
+
title,
|
|
22
|
+
onOpenChange,
|
|
23
|
+
children,
|
|
24
|
+
description,
|
|
25
|
+
footer,
|
|
26
|
+
showCloseButton = true,
|
|
27
|
+
size = 'md',
|
|
28
|
+
class: className,
|
|
29
|
+
}: Props = $props()
|
|
30
|
+
|
|
31
|
+
function handleOpenChange(newOpen: boolean) {
|
|
32
|
+
open = newOpen
|
|
33
|
+
onOpenChange?.(newOpen)
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<Dialog.Root {open} onOpenChange={handleOpenChange}>
|
|
38
|
+
<Dialog.Portal>
|
|
39
|
+
<Dialog.Overlay class="fixed inset-0 bg-overlay z-14 animate-fade-in motion-reduce:animate-none" />
|
|
40
|
+
<Dialog.Content
|
|
41
|
+
class={cn(
|
|
42
|
+
'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-surface rounded-12 shadow-modal w-[calc(100%-20px)] max-h-[90vh] flex flex-col z-15 animate-modal-in motion-reduce:animate-none',
|
|
43
|
+
size === 'sm' && 'max-w-400',
|
|
44
|
+
size === 'md' && 'max-w-500',
|
|
45
|
+
size === 'lg' && 'max-w-700',
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
>
|
|
49
|
+
<div class="flex items-center justify-between p-16 border-b border-primary shrink-0">
|
|
50
|
+
<div>
|
|
51
|
+
<Dialog.Title class="text-h4 text-body m-0">{title}</Dialog.Title>
|
|
52
|
+
{#if description}
|
|
53
|
+
<Dialog.Description class="text-small text-secondary mt-4">
|
|
54
|
+
{@render description()}
|
|
55
|
+
</Dialog.Description>
|
|
56
|
+
{/if}
|
|
57
|
+
</div>
|
|
58
|
+
{#if showCloseButton}
|
|
59
|
+
<Dialog.Close
|
|
60
|
+
class="[all:unset] cursor-default flex items-center justify-center p-4 rounded-4 text-secondary transition-all duration-fast hover:bg-background hover:text-body motion-reduce:transition-none"
|
|
61
|
+
>
|
|
62
|
+
<IconClose class="size-20" />
|
|
63
|
+
</Dialog.Close>
|
|
64
|
+
{/if}
|
|
65
|
+
</div>
|
|
66
|
+
<div class="p-16 flex-auto min-h-0 overflow-y-auto">
|
|
67
|
+
{@render children()}
|
|
68
|
+
</div>
|
|
69
|
+
{#if footer}
|
|
70
|
+
<div class="flex items-center justify-end gap-12 p-16 border-t border-primary shrink-0">
|
|
71
|
+
{@render footer()}
|
|
72
|
+
</div>
|
|
73
|
+
{/if}
|
|
74
|
+
</Dialog.Content>
|
|
75
|
+
</Dialog.Portal>
|
|
76
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
title: string;
|
|
5
|
+
onOpenChange?: (open: boolean) => void;
|
|
6
|
+
children: Snippet;
|
|
7
|
+
description?: Snippet;
|
|
8
|
+
footer?: Snippet;
|
|
9
|
+
showCloseButton?: boolean;
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
class?: string;
|
|
12
|
+
};
|
|
13
|
+
declare const IIModal: import("svelte").Component<Props, {}, "open">;
|
|
14
|
+
type IIModal = ReturnType<typeof IIModal>;
|
|
15
|
+
export default IIModal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIModal } from './IIModal.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIModal } from './IIModal.svelte';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type {Snippet} from 'svelte'
|
|
3
|
+
import {DropdownMenu} from 'bits-ui'
|
|
4
|
+
import {IIButton} from '../IIButton'
|
|
5
|
+
import {cn} from '../utils/cn'
|
|
6
|
+
import {IconMoreVert} from '../icons'
|
|
7
|
+
|
|
8
|
+
type Action = {
|
|
9
|
+
label: string
|
|
10
|
+
onclick: () => void
|
|
11
|
+
disabled?: boolean
|
|
12
|
+
variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'success'
|
|
13
|
+
icon?: Snippet
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type Props = {
|
|
17
|
+
actions: Action[]
|
|
18
|
+
size?: 'sm' | 'md' | 'lg'
|
|
19
|
+
class?: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let {actions, size = 'md', class: className}: Props = $props()
|
|
23
|
+
|
|
24
|
+
let wrapperEl = $state<HTMLElement | null>(null)
|
|
25
|
+
let overflowing = $state(false)
|
|
26
|
+
let kebabOpen = $state(false)
|
|
27
|
+
|
|
28
|
+
// Plain variable (not reactive) so it doesn't re-trigger the effect
|
|
29
|
+
let buttonsNaturalWidth = 0
|
|
30
|
+
|
|
31
|
+
$effect(() => {
|
|
32
|
+
if (!wrapperEl) return
|
|
33
|
+
|
|
34
|
+
// On first render, buttons are visible — capture their natural width
|
|
35
|
+
if (buttonsNaturalWidth === 0) {
|
|
36
|
+
const inlineEl = wrapperEl.querySelector('.ii-overflow-inline') as HTMLElement | null
|
|
37
|
+
if (inlineEl) {
|
|
38
|
+
buttonsNaturalWidth = inlineEl.scrollWidth
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (buttonsNaturalWidth === 0) return
|
|
43
|
+
|
|
44
|
+
const BUFFER = 32
|
|
45
|
+
const HYSTERESIS = 16
|
|
46
|
+
|
|
47
|
+
function check() {
|
|
48
|
+
if (!wrapperEl) return
|
|
49
|
+
const width = wrapperEl.clientWidth
|
|
50
|
+
if (overflowing) {
|
|
51
|
+
// Require extra room before switching back to buttons
|
|
52
|
+
overflowing = width < buttonsNaturalWidth + BUFFER + HYSTERESIS
|
|
53
|
+
} else {
|
|
54
|
+
// Collapse early so buttons never visibly clip
|
|
55
|
+
overflowing = width < buttonsNaturalWidth + BUFFER
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
check()
|
|
60
|
+
const observer = new ResizeObserver(check)
|
|
61
|
+
observer.observe(wrapperEl)
|
|
62
|
+
return () => observer.disconnect()
|
|
63
|
+
})
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<div class={cn('flex items-center justify-end flex-1 min-w-0 overflow-hidden', className)} bind:this={wrapperEl}>
|
|
67
|
+
{#if overflowing}
|
|
68
|
+
<DropdownMenu.Root bind:open={kebabOpen}>
|
|
69
|
+
<DropdownMenu.Trigger
|
|
70
|
+
class="[all:unset] cursor-default inline-flex items-center justify-center p-4 rounded-4 text-secondary text-h3 transition-all duration-fast hover:bg-background hover:text-body data-[state=open]:bg-background data-[state=open]:text-body motion-reduce:transition-none"
|
|
71
|
+
>
|
|
72
|
+
<IconMoreVert />
|
|
73
|
+
</DropdownMenu.Trigger>
|
|
74
|
+
<DropdownMenu.Content
|
|
75
|
+
class="min-w-100 bg-surface border border-primary rounded-10 shadow-dropdown p-4 z-12"
|
|
76
|
+
side="bottom"
|
|
77
|
+
align="end"
|
|
78
|
+
>
|
|
79
|
+
{#each actions as action (action.label)}
|
|
80
|
+
<DropdownMenu.Item
|
|
81
|
+
disabled={action.disabled}
|
|
82
|
+
class="flex items-center gap-8 px-12 py-8 rounded-4 text-small-emphasis text-body cursor-default outline-none transition-all duration-fast hover:bg-background data-[highlighted]:bg-background data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed data-[disabled]:pointer-events-none motion-reduce:transition-none"
|
|
83
|
+
onSelect={action.onclick}
|
|
84
|
+
>
|
|
85
|
+
<span>{action.label}</span>
|
|
86
|
+
</DropdownMenu.Item>
|
|
87
|
+
{/each}
|
|
88
|
+
</DropdownMenu.Content>
|
|
89
|
+
</DropdownMenu.Root>
|
|
90
|
+
{:else}
|
|
91
|
+
<div class="flex gap-8 items-center shrink-0">
|
|
92
|
+
{#each actions as action (action.label)}
|
|
93
|
+
<IIButton variant={action.variant ?? 'primary'} {size} onclick={action.onclick} disabled={action.disabled}>
|
|
94
|
+
{#if action.icon}
|
|
95
|
+
<span class="inline-flex items-center w-16 h-16 [&_svg]:w-full [&_svg]:h-full">
|
|
96
|
+
{@render action.icon()}
|
|
97
|
+
</span>
|
|
98
|
+
{/if}
|
|
99
|
+
{action.label}
|
|
100
|
+
</IIButton>
|
|
101
|
+
{/each}
|
|
102
|
+
</div>
|
|
103
|
+
{/if}
|
|
104
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
type Action = {
|
|
3
|
+
label: string;
|
|
4
|
+
onclick: () => void;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'success';
|
|
7
|
+
icon?: Snippet;
|
|
8
|
+
};
|
|
9
|
+
type Props = {
|
|
10
|
+
actions: Action[];
|
|
11
|
+
size?: 'sm' | 'md' | 'lg';
|
|
12
|
+
class?: string;
|
|
13
|
+
};
|
|
14
|
+
declare const IIOverflowActions: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type IIOverflowActions = ReturnType<typeof IIOverflowActions>;
|
|
16
|
+
export default IIOverflowActions;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIOverflowActions } from './IIOverflowActions.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIOverflowActions } from './IIOverflowActions.svelte';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {cn} from '../utils/cn'
|
|
3
|
+
|
|
4
|
+
type RiskLevel = 'current' | 'attention' | 'at-risk'
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
level: RiskLevel
|
|
8
|
+
label: string
|
|
9
|
+
tooltip?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
let {level, label, tooltip}: Props = $props()
|
|
13
|
+
|
|
14
|
+
const levelClasses: Record<string, string> = {
|
|
15
|
+
current: 'bg-success-bg text-success',
|
|
16
|
+
attention: 'bg-warning-bg text-warning',
|
|
17
|
+
'at-risk': 'bg-error-bg text-error',
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<span
|
|
22
|
+
class={cn(
|
|
23
|
+
'inline-flex items-center px-12 py-4 rounded-full text-tiny-strong whitespace-nowrap transition-all duration-base motion-reduce:transition-none',
|
|
24
|
+
levelClasses[level]
|
|
25
|
+
)}
|
|
26
|
+
title={tooltip}
|
|
27
|
+
>
|
|
28
|
+
{label}
|
|
29
|
+
</span>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type RiskLevel = 'current' | 'attention' | 'at-risk';
|
|
2
|
+
type Props = {
|
|
3
|
+
level: RiskLevel;
|
|
4
|
+
label: string;
|
|
5
|
+
tooltip?: string;
|
|
6
|
+
};
|
|
7
|
+
declare const IIStatusBadge: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type IIStatusBadge = ReturnType<typeof IIStatusBadge>;
|
|
9
|
+
export default IIStatusBadge;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as IIStatusBadge } from './IIStatusBadge.svelte';
|