@ibis-design/svelte 0.2.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/dist/components/buttons/Button.svelte +106 -0
- package/dist/components/buttons/Button.svelte.d.ts +69 -0
- package/dist/components/buttons/DropdownButton.svelte +91 -0
- package/dist/components/buttons/DropdownButton.svelte.d.ts +33 -0
- package/dist/components/buttons/PillTab.svelte +84 -0
- package/dist/components/buttons/PillTab.svelte.d.ts +55 -0
- package/dist/components/buttons/button.css +193 -0
- package/dist/components/buttons/dropdownButton.css +82 -0
- package/dist/components/buttons/pillTab.css +59 -0
- package/dist/components/containers/Banner.svelte +73 -0
- package/dist/components/containers/Banner.svelte.d.ts +16 -0
- package/dist/components/containers/Card.svelte +34 -0
- package/dist/components/containers/Card.svelte.d.ts +14 -0
- package/dist/components/containers/PillTabs.svelte +22 -0
- package/dist/components/containers/PillTabs.svelte.d.ts +6 -0
- package/dist/components/containers/TipIndicator.svelte +78 -0
- package/dist/components/containers/TipIndicator.svelte.d.ts +28 -0
- package/dist/components/containers/Toaster.svelte +75 -0
- package/dist/components/containers/Toaster.svelte.d.ts +16 -0
- package/dist/components/containers/Tooltip.svelte.d.ts +26 -0
- package/dist/components/containers/banner.css +155 -0
- package/dist/components/containers/tipIndicator.css +79 -0
- package/dist/components/containers/toaster.css +137 -0
- package/dist/components/containers/tooltip.css +0 -0
- package/dist/components/inputs/.gitkeep +0 -0
- package/dist/components/inputs/Checkbox.svelte +95 -0
- package/dist/components/inputs/Checkbox.svelte.d.ts +33 -0
- package/dist/components/inputs/Chips.svelte +104 -0
- package/dist/components/inputs/Chips.svelte.d.ts +48 -0
- package/dist/components/inputs/Dropdown.svelte +83 -0
- package/dist/components/inputs/Dropdown.svelte.d.ts +15 -0
- package/dist/components/inputs/Radio.svelte +109 -0
- package/dist/components/inputs/Radio.svelte.d.ts +49 -0
- package/dist/components/inputs/Switch.svelte +45 -0
- package/dist/components/inputs/Switch.svelte.d.ts +21 -0
- package/dist/components/inputs/TextArea.svelte +65 -0
- package/dist/components/inputs/TextArea.svelte.d.ts +14 -0
- package/dist/components/inputs/TextInput.svelte +273 -0
- package/dist/components/inputs/TextInput.svelte.d.ts +140 -0
- package/dist/components/inputs/TextLink.svelte +102 -0
- package/dist/components/inputs/TextLink.svelte.d.ts +21 -0
- package/dist/components/inputs/checkbox.css +103 -0
- package/dist/components/inputs/chips.css +76 -0
- package/dist/components/inputs/dropdown.css +106 -0
- package/dist/components/inputs/radio.css +108 -0
- package/dist/components/inputs/switch.css +68 -0
- package/dist/components/inputs/textInput.css +152 -0
- package/dist/components/inputs/textarea.css +91 -0
- package/dist/components/inputs/textlink.css +163 -0
- package/dist/index.d.ts +21 -8
- package/dist/index.js +36 -2000
- package/dist/layouts/AppLayout.svelte +83 -0
- package/dist/layouts/AppLayout.svelte.d.ts +20 -0
- package/dist/layouts/AuthLayout.svelte +63 -0
- package/dist/layouts/AuthLayout.svelte.d.ts +18 -0
- package/dist/layouts/DashboardLayout.svelte +88 -0
- package/dist/layouts/DashboardLayout.svelte.d.ts +20 -0
- package/dist/types/button.js +5 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +5 -0
- package/dist/types/layout.d.ts +1 -1
- package/dist/types/layout.js +1 -0
- package/package.json +49 -44
- package/dist/index.css +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/components/buttons/Button.svelte.d.ts +0 -1
- package/dist/lib/components/buttons/DropdownButton.svelte.d.ts +0 -1
- package/dist/lib/components/containers/Card.svelte.d.ts +0 -1
- package/dist/lib/layouts/AppLayout.svelte.d.ts +0 -1
- package/dist/lib/layouts/AuthLayout.svelte.d.ts +0 -1
- package/dist/lib/layouts/DashboardLayout.svelte.d.ts +0 -1
- /package/dist/{types/input.d.ts → components/containers/Tooltip.svelte} +0 -0
package/README.md
CHANGED
|
@@ -115,16 +115,26 @@ With inline snippets:
|
|
|
115
115
|
|
|
116
116
|
## Build
|
|
117
117
|
|
|
118
|
+
This package is built with **`@sveltejs/package`** (`svelte-package`), the supported Svelte library pipeline. It preprocesses Svelte, transpiles TypeScript, and emits **`.d.ts` next to outputs** so consumers get correct component prop types (not a separate Vite “library mode” + `vite-plugin-dts` flow).
|
|
119
|
+
|
|
118
120
|
From the package directory:
|
|
119
121
|
|
|
120
122
|
```bash
|
|
121
123
|
npm run build
|
|
122
124
|
```
|
|
123
125
|
|
|
126
|
+
This runs `svelte-kit sync` (generates `.svelte-kit` types for the minimal Kit shell) then `svelte-package`, writing output to `dist/`.
|
|
127
|
+
|
|
128
|
+
Watch mode during development:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npm run dev
|
|
132
|
+
```
|
|
133
|
+
|
|
124
134
|
From the monorepo root:
|
|
125
135
|
|
|
126
136
|
```bash
|
|
127
|
-
npm run build
|
|
137
|
+
npm run build -w @ibis-design/svelte
|
|
128
138
|
```
|
|
129
139
|
|
|
130
140
|
## Type checking
|
|
@@ -133,4 +143,4 @@ npm run build --workspaces
|
|
|
133
143
|
npm run check
|
|
134
144
|
```
|
|
135
145
|
|
|
136
|
-
Runs `svelte-check` with the package `tsconfig.json`.
|
|
146
|
+
Runs `svelte-kit sync` then `svelte-check` with the package `tsconfig.json`.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import './button.css';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
import type { ButtonVariant, ButtonSize } from '../../types/button';
|
|
5
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
6
|
+
|
|
7
|
+
interface Props extends HTMLButtonAttributes {
|
|
8
|
+
/**
|
|
9
|
+
* Native button variants.
|
|
10
|
+
*
|
|
11
|
+
* Determines the visual style of the button, affecting its colors and borders.
|
|
12
|
+
*
|
|
13
|
+
* @default "primary"
|
|
14
|
+
* @example
|
|
15
|
+
* - `primary`: <Button variant="primary">Save</Button>
|
|
16
|
+
* - `secondary`: <Button variant="secondary">Cancel</Button>
|
|
17
|
+
*/
|
|
18
|
+
variant?: ButtonVariant;
|
|
19
|
+
/**
|
|
20
|
+
* Native button sizes.
|
|
21
|
+
*
|
|
22
|
+
* Determines the size of the button, affecting its padding and font size.
|
|
23
|
+
*
|
|
24
|
+
* @default "md"
|
|
25
|
+
* @example
|
|
26
|
+
* - `sm`: <Button size="sm">Small</Button>
|
|
27
|
+
* - `md`: <Button size="md">Medium</Button>
|
|
28
|
+
* - `lg`: <Button size="lg">Large</Button>
|
|
29
|
+
*/
|
|
30
|
+
size?: ButtonSize;
|
|
31
|
+
/**
|
|
32
|
+
* Native button behavior types.
|
|
33
|
+
*
|
|
34
|
+
* Determines how the button behaves when clicked.
|
|
35
|
+
*
|
|
36
|
+
* @default "button"
|
|
37
|
+
* @remarks
|
|
38
|
+
* Use `submit` for form submission and `reset` to clear form fields.
|
|
39
|
+
* Avoid using `submit` for non-form actions
|
|
40
|
+
*/
|
|
41
|
+
type?: 'button' | 'submit' | 'reset';
|
|
42
|
+
/**
|
|
43
|
+
* Disables the button, preventing user interaction and applying disabled styles.
|
|
44
|
+
*
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Shows a loading spinner and disables the button to indicate an ongoing action.
|
|
50
|
+
*
|
|
51
|
+
* @default false
|
|
52
|
+
*/
|
|
53
|
+
loading?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Applies a skeleton loading state to the button, showing a placeholder style while content is loading.
|
|
56
|
+
*
|
|
57
|
+
* @default false`
|
|
58
|
+
*/
|
|
59
|
+
skeleton?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* If true, the button is styled for icon-only content, removing extra padding and centering the icon.
|
|
62
|
+
*
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
iconOnly?: boolean;
|
|
66
|
+
label?: string;
|
|
67
|
+
children?: Snippet;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
let {
|
|
71
|
+
variant = 'primary',
|
|
72
|
+
size = 'md',
|
|
73
|
+
type = 'button',
|
|
74
|
+
disabled = false,
|
|
75
|
+
loading = false,
|
|
76
|
+
skeleton = false,
|
|
77
|
+
iconOnly = false,
|
|
78
|
+
label,
|
|
79
|
+
children,
|
|
80
|
+
...rest
|
|
81
|
+
}: Props = $props();
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
<button
|
|
85
|
+
{...rest}
|
|
86
|
+
{type}
|
|
87
|
+
{disabled}
|
|
88
|
+
aria-busy={loading}
|
|
89
|
+
class="ibis-button
|
|
90
|
+
ibis-button--{variant}
|
|
91
|
+
ibis-button--{size}
|
|
92
|
+
{loading ? 'ibis-button--loading' : ''}
|
|
93
|
+
{skeleton ? 'ibis-button--skeleton' : ''}
|
|
94
|
+
{iconOnly ? 'ibis-button--icon-only' : ''}"
|
|
95
|
+
>
|
|
96
|
+
<span class="ibis-button__content {loading || skeleton ? 'ibis-button__content--hidden' : ''}">
|
|
97
|
+
{#if children}
|
|
98
|
+
{@render children?.()}
|
|
99
|
+
{:else if label}
|
|
100
|
+
{label}
|
|
101
|
+
{/if}
|
|
102
|
+
</span>
|
|
103
|
+
{#if loading}
|
|
104
|
+
<span class="ibis-button__loader" aria-hidden="true"></span>
|
|
105
|
+
{/if}
|
|
106
|
+
</button>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import './button.css';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { ButtonVariant, ButtonSize } from '../../types/button';
|
|
4
|
+
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
5
|
+
interface Props extends HTMLButtonAttributes {
|
|
6
|
+
/**
|
|
7
|
+
* Native button variants.
|
|
8
|
+
*
|
|
9
|
+
* Determines the visual style of the button, affecting its colors and borders.
|
|
10
|
+
*
|
|
11
|
+
* @default "primary"
|
|
12
|
+
* @example
|
|
13
|
+
* - `primary`: <Button variant="primary">Save</Button>
|
|
14
|
+
* - `secondary`: <Button variant="secondary">Cancel</Button>
|
|
15
|
+
*/
|
|
16
|
+
variant?: ButtonVariant;
|
|
17
|
+
/**
|
|
18
|
+
* Native button sizes.
|
|
19
|
+
*
|
|
20
|
+
* Determines the size of the button, affecting its padding and font size.
|
|
21
|
+
*
|
|
22
|
+
* @default "md"
|
|
23
|
+
* @example
|
|
24
|
+
* - `sm`: <Button size="sm">Small</Button>
|
|
25
|
+
* - `md`: <Button size="md">Medium</Button>
|
|
26
|
+
* - `lg`: <Button size="lg">Large</Button>
|
|
27
|
+
*/
|
|
28
|
+
size?: ButtonSize;
|
|
29
|
+
/**
|
|
30
|
+
* Native button behavior types.
|
|
31
|
+
*
|
|
32
|
+
* Determines how the button behaves when clicked.
|
|
33
|
+
*
|
|
34
|
+
* @default "button"
|
|
35
|
+
* @remarks
|
|
36
|
+
* Use `submit` for form submission and `reset` to clear form fields.
|
|
37
|
+
* Avoid using `submit` for non-form actions
|
|
38
|
+
*/
|
|
39
|
+
type?: 'button' | 'submit' | 'reset';
|
|
40
|
+
/**
|
|
41
|
+
* Disables the button, preventing user interaction and applying disabled styles.
|
|
42
|
+
*
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
disabled?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Shows a loading spinner and disables the button to indicate an ongoing action.
|
|
48
|
+
*
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
loading?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Applies a skeleton loading state to the button, showing a placeholder style while content is loading.
|
|
54
|
+
*
|
|
55
|
+
* @default false`
|
|
56
|
+
*/
|
|
57
|
+
skeleton?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* If true, the button is styled for icon-only content, removing extra padding and centering the icon.
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
iconOnly?: boolean;
|
|
64
|
+
label?: string;
|
|
65
|
+
children?: Snippet;
|
|
66
|
+
}
|
|
67
|
+
declare const Button: import("svelte").Component<Props, {}, "">;
|
|
68
|
+
type Button = ReturnType<typeof Button>;
|
|
69
|
+
export default Button;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import './dropdownButton.css';
|
|
3
|
+
import Button from './Button.svelte';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
/**
|
|
8
|
+
* The label shown in the trigger button when an option is selected.
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Placeholder text shown in the trigger button when no option is selected.
|
|
13
|
+
*
|
|
14
|
+
* @default "Select..."
|
|
15
|
+
*/
|
|
16
|
+
placeholder?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Custom trigger content via Snippet.
|
|
19
|
+
* Falls back to label or placeholder if not provided.
|
|
20
|
+
*/
|
|
21
|
+
trigger?: Snippet;
|
|
22
|
+
/**
|
|
23
|
+
* Custom menu content via Snippet.
|
|
24
|
+
* Use this to pass menu items.
|
|
25
|
+
*/
|
|
26
|
+
menu?: Snippet<[close: () => void]>;
|
|
27
|
+
/**
|
|
28
|
+
* Disables the dropdown, preventing interaction.
|
|
29
|
+
*
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let { label, placeholder = 'Select...', trigger, menu, disabled = false }: Props = $props();
|
|
36
|
+
|
|
37
|
+
let open = $state(false);
|
|
38
|
+
let dropdownRef = $state<HTMLDivElement | null>(null);
|
|
39
|
+
|
|
40
|
+
const menuId = `ibis-dropdown-button-${Math.random().toString(36).slice(2)}`;
|
|
41
|
+
|
|
42
|
+
const toggle = () => {
|
|
43
|
+
if (disabled) return;
|
|
44
|
+
open = !open;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleKeydown = (e: KeyboardEvent) => {
|
|
48
|
+
if (e.key === 'Escape') open = false;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleClickOutside = (e: MouseEvent) => {
|
|
52
|
+
if (dropdownRef && !dropdownRef.contains(e.target as Node)) {
|
|
53
|
+
open = false;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<svelte:window onclick={handleClickOutside} />
|
|
59
|
+
|
|
60
|
+
<div
|
|
61
|
+
class="dropdown-button {open ? 'dropdown-button--open' : ''}"
|
|
62
|
+
bind:this={dropdownRef}
|
|
63
|
+
onkeydown={handleKeydown}
|
|
64
|
+
role="combobox"
|
|
65
|
+
tabindex="0"
|
|
66
|
+
aria-expanded={open}
|
|
67
|
+
aria-haspopup="listbox"
|
|
68
|
+
aria-controls={menuId}
|
|
69
|
+
>
|
|
70
|
+
<!-- Trigger -->
|
|
71
|
+
<Button onclick={toggle} {disabled}>
|
|
72
|
+
{#if trigger}
|
|
73
|
+
{@render trigger()}
|
|
74
|
+
{:else}
|
|
75
|
+
{label || placeholder}
|
|
76
|
+
{/if}
|
|
77
|
+
|
|
78
|
+
<svg class="caret {open ? 'caret--open' : ''}" viewBox="0 0 16 16" aria-hidden="true">
|
|
79
|
+
<path d="M4 6l4 4 4-4" stroke="currentColor" stroke-width="2" fill="none" />
|
|
80
|
+
</svg>
|
|
81
|
+
</Button>
|
|
82
|
+
|
|
83
|
+
<!-- Menu -->
|
|
84
|
+
{#if open}
|
|
85
|
+
<ul class="dropdown-menu" role="listbox">
|
|
86
|
+
{#if menu}
|
|
87
|
+
{@render menu(() => (open = false))}
|
|
88
|
+
{/if}
|
|
89
|
+
</ul>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import './dropdownButton.css';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
/**
|
|
5
|
+
* The label shown in the trigger button when an option is selected.
|
|
6
|
+
*/
|
|
7
|
+
label?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Placeholder text shown in the trigger button when no option is selected.
|
|
10
|
+
*
|
|
11
|
+
* @default "Select..."
|
|
12
|
+
*/
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Custom trigger content via Snippet.
|
|
16
|
+
* Falls back to label or placeholder if not provided.
|
|
17
|
+
*/
|
|
18
|
+
trigger?: Snippet;
|
|
19
|
+
/**
|
|
20
|
+
* Custom menu content via Snippet.
|
|
21
|
+
* Use this to pass menu items.
|
|
22
|
+
*/
|
|
23
|
+
menu?: Snippet<[close: () => void]>;
|
|
24
|
+
/**
|
|
25
|
+
* Disables the dropdown, preventing interaction.
|
|
26
|
+
*
|
|
27
|
+
* @default false
|
|
28
|
+
*/
|
|
29
|
+
disabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
declare const DropdownButton: import("svelte").Component<Props, {}, "">;
|
|
32
|
+
type DropdownButton = ReturnType<typeof DropdownButton>;
|
|
33
|
+
export default DropdownButton;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import './pillTab.css';
|
|
3
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLInputAttributes {
|
|
6
|
+
/**
|
|
7
|
+
* The visible text label displayed inside the pill tab.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <PillTab label="Overview" value="overview" />
|
|
11
|
+
*/
|
|
12
|
+
label?: string;
|
|
13
|
+
/**
|
|
14
|
+
* The unique identifier for the input element.
|
|
15
|
+
*
|
|
16
|
+
* If not provided, a random ID is generated automatically.
|
|
17
|
+
*/
|
|
18
|
+
id?: string;
|
|
19
|
+
/**
|
|
20
|
+
* The currently selected value in the radio group.
|
|
21
|
+
*
|
|
22
|
+
* When `group` matches `value`, the pill tab appears active.
|
|
23
|
+
* Bind this to a shared variable across all tabs in the same group.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* <PillTab bind:group={activeTab} value="overview" label="Overview" />
|
|
27
|
+
*/
|
|
28
|
+
group?: string | number;
|
|
29
|
+
/**
|
|
30
|
+
* The value this pill tab represents in the radio group.
|
|
31
|
+
*
|
|
32
|
+
* When `group === value`, this tab is considered active.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* <PillTab value="settings" label="Settings" />
|
|
36
|
+
*/
|
|
37
|
+
value: string | number;
|
|
38
|
+
/**
|
|
39
|
+
* The name attribute shared across all radio inputs in the same group.
|
|
40
|
+
*
|
|
41
|
+
* Required for native radio group behavior — all tabs in the same
|
|
42
|
+
* group must share the same `name`.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* <PillTab name="main-nav" value="overview" label="Overview" />
|
|
46
|
+
*/
|
|
47
|
+
name?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Disables the pill tab, preventing user interaction and applying disabled styles.
|
|
50
|
+
*
|
|
51
|
+
* @default false
|
|
52
|
+
*/
|
|
53
|
+
disabled?: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let { id, label, group = $bindable(), value, name, disabled = false, ...rest }: Props = $props();
|
|
57
|
+
|
|
58
|
+
const fallbackId = `ibis-pill-tab-${Math.random().toString(36).slice(2)}`;
|
|
59
|
+
const inputId = $derived(id ?? fallbackId);
|
|
60
|
+
|
|
61
|
+
const checked = $derived(group === value);
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<label
|
|
65
|
+
class="ibis-pill-tab
|
|
66
|
+
{checked ? 'ibis-pill-tab--active' : ''}
|
|
67
|
+
{disabled ? 'ibis-pill-tab--disabled' : ''}"
|
|
68
|
+
for={inputId}
|
|
69
|
+
>
|
|
70
|
+
<input
|
|
71
|
+
{...rest}
|
|
72
|
+
id={inputId}
|
|
73
|
+
type="radio"
|
|
74
|
+
{name}
|
|
75
|
+
bind:group
|
|
76
|
+
{value}
|
|
77
|
+
{disabled}
|
|
78
|
+
class="ibis-pill-tab__input"
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
<span class="ibis-pill-tab__content">
|
|
82
|
+
{label}
|
|
83
|
+
</span>
|
|
84
|
+
</label>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import './pillTab.css';
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props extends HTMLInputAttributes {
|
|
4
|
+
/**
|
|
5
|
+
* The visible text label displayed inside the pill tab.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* <PillTab label="Overview" value="overview" />
|
|
9
|
+
*/
|
|
10
|
+
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The unique identifier for the input element.
|
|
13
|
+
*
|
|
14
|
+
* If not provided, a random ID is generated automatically.
|
|
15
|
+
*/
|
|
16
|
+
id?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The currently selected value in the radio group.
|
|
19
|
+
*
|
|
20
|
+
* When `group` matches `value`, the pill tab appears active.
|
|
21
|
+
* Bind this to a shared variable across all tabs in the same group.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* <PillTab bind:group={activeTab} value="overview" label="Overview" />
|
|
25
|
+
*/
|
|
26
|
+
group?: string | number;
|
|
27
|
+
/**
|
|
28
|
+
* The value this pill tab represents in the radio group.
|
|
29
|
+
*
|
|
30
|
+
* When `group === value`, this tab is considered active.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* <PillTab value="settings" label="Settings" />
|
|
34
|
+
*/
|
|
35
|
+
value: string | number;
|
|
36
|
+
/**
|
|
37
|
+
* The name attribute shared across all radio inputs in the same group.
|
|
38
|
+
*
|
|
39
|
+
* Required for native radio group behavior — all tabs in the same
|
|
40
|
+
* group must share the same `name`.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* <PillTab name="main-nav" value="overview" label="Overview" />
|
|
44
|
+
*/
|
|
45
|
+
name?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Disables the pill tab, preventing user interaction and applying disabled styles.
|
|
48
|
+
*
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
}
|
|
53
|
+
declare const PillTab: import("svelte").Component<Props, {}, "group">;
|
|
54
|
+
type PillTab = ReturnType<typeof PillTab>;
|
|
55
|
+
export default PillTab;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
.ibis-button {
|
|
2
|
+
font-family: var(--font-family-sans);
|
|
3
|
+
font-weight: var(--font-weight-normal);
|
|
4
|
+
border: var(--border-width-default) solid transparent;
|
|
5
|
+
cursor: pointer;
|
|
6
|
+
transition:
|
|
7
|
+
filter var(--transition-duration-fast) var(--transition-timing-default),
|
|
8
|
+
transform var(--transition-duration-fast) var(--transition-timing-default),
|
|
9
|
+
box-shadow var(--transition-duration-fast) var(--transition-timing-default);
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.ibis-button :global(svg) {
|
|
16
|
+
width: 1em;
|
|
17
|
+
height: 1em;
|
|
18
|
+
display: inline-block;
|
|
19
|
+
vertical-align: middle;
|
|
20
|
+
gap: var(--spacing-1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Content Layout */
|
|
24
|
+
.ibis-button__content {
|
|
25
|
+
display: inline-flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
gap: var(--spacing-1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.ibis-button__content--hidden {
|
|
32
|
+
visibility: hidden;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* Icon Only */
|
|
36
|
+
.ibis-button--icon-only {
|
|
37
|
+
padding: var(--spacing-2);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.ibis-button--icon-only .ibis-button__content {
|
|
41
|
+
gap: 0;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Disabled State */
|
|
45
|
+
.ibis-button:disabled {
|
|
46
|
+
opacity: var(--opacity-disabled);
|
|
47
|
+
cursor: not-allowed;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Loading State */
|
|
51
|
+
.ibis-button--loading {
|
|
52
|
+
position: relative;
|
|
53
|
+
cursor: not-allowed;
|
|
54
|
+
pointer-events: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Primary Variant */
|
|
58
|
+
.ibis-button--primary {
|
|
59
|
+
background: linear-gradient(180deg, #9665df 0%, #7945c8 100%); /* Hardcoded */
|
|
60
|
+
color: var(--color-white);
|
|
61
|
+
|
|
62
|
+
box-shadow: var(--component-button-primary-default-shadow);
|
|
63
|
+
border: 0.5px solid #bd91ff; /* Hardcoded */
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.ibis-button--primary:not(:disabled):hover,
|
|
67
|
+
.ibis-button--primary:not(:disabled):active {
|
|
68
|
+
box-shadow: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.ibis-button--primary:not(:disabled):hover {
|
|
72
|
+
background: var(--color-primary-800);
|
|
73
|
+
border-color: none;
|
|
74
|
+
border-width: 0.7 px; /* Hardcoded */
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.ibis-button--primary:not(:disabled):active {
|
|
78
|
+
background: var(--color-primary-800);
|
|
79
|
+
border-color: var(--color-primary-400);
|
|
80
|
+
border-width: var(--border-width-thin);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.ibis-button--primary:disabled {
|
|
84
|
+
background: var(--color-neutral-400);
|
|
85
|
+
color: var(--color-neutral-600);
|
|
86
|
+
border-color: var(--color-neutral-600);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Secondary Variant */
|
|
90
|
+
.ibis-button--secondary {
|
|
91
|
+
background-color: transparent;
|
|
92
|
+
color: var(--color-primary-pink-500);
|
|
93
|
+
border-color: var(--color-primary-pink-700);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.ibis-button--secondary:not(:disabled):hover {
|
|
97
|
+
background-color: var(--color-primary-pink-100);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Variant Sizes */
|
|
101
|
+
.ibis-button--sm {
|
|
102
|
+
padding: var(--spacing-1) var(--spacing-2);
|
|
103
|
+
font-size: var(--font-size-normal-text-sm);
|
|
104
|
+
border-radius: var(--component-button-size-sm-border-radius);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.ibis-button--md {
|
|
108
|
+
padding: var(--spacing-2) var(--spacing-4);
|
|
109
|
+
font-size: var(--font-size-normal-text-DEFAULT);
|
|
110
|
+
border-radius: var(--component-button-size-md-border-radius);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.ibis-button--lg {
|
|
114
|
+
padding: var(--spacing-3) var(--spacing-6);
|
|
115
|
+
font-size: var(--font-size-normal-text-lg);
|
|
116
|
+
border-radius: var(--component-button-size-lg-border-radius);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Loader Spinner */
|
|
120
|
+
.ibis-button__loader {
|
|
121
|
+
position: absolute;
|
|
122
|
+
width: 1em;
|
|
123
|
+
height: 1em;
|
|
124
|
+
border: var(--border-width-default) solid var(--color-black);
|
|
125
|
+
border-top-color: var(--color-white);
|
|
126
|
+
border-radius: 50%;
|
|
127
|
+
animation: ibis-spin 0.8s linear infinite;
|
|
128
|
+
top: 50%;
|
|
129
|
+
left: 50%;
|
|
130
|
+
transform: translate(-50%, -50%);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@keyframes ibis-spin {
|
|
134
|
+
from {
|
|
135
|
+
transform: translate(-50%, -50%) rotate(0deg);
|
|
136
|
+
}
|
|
137
|
+
to {
|
|
138
|
+
transform: translate(-50%, -50%) rotate(360deg);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* Skeleton State */
|
|
143
|
+
.ibis-button--skeleton {
|
|
144
|
+
position: relative;
|
|
145
|
+
overflow: hidden;
|
|
146
|
+
background: var(--color-neutral-200);
|
|
147
|
+
color: transparent;
|
|
148
|
+
border-color: var(--color-neutral-500);
|
|
149
|
+
cursor: default;
|
|
150
|
+
pointer-events: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.ibis-button--skeleton::after {
|
|
154
|
+
content: '';
|
|
155
|
+
position: absolute;
|
|
156
|
+
top: 50%;
|
|
157
|
+
left: 50%;
|
|
158
|
+
transform: translate(-50%, -50%);
|
|
159
|
+
width: 80%;
|
|
160
|
+
height: 1em;
|
|
161
|
+
background-color: var(--color-neutral-400);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.ibis-button--icon-only--skeleton::after {
|
|
165
|
+
width: 1em;
|
|
166
|
+
height: 1em;
|
|
167
|
+
border-radius: 4px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.ibis-button--skeleton::before {
|
|
171
|
+
content: '';
|
|
172
|
+
position: absolute;
|
|
173
|
+
inset: 0;
|
|
174
|
+
background: linear-gradient(
|
|
175
|
+
90deg,
|
|
176
|
+
rgba(255, 255, 255, 0.25) 0%,
|
|
177
|
+
rgba(255, 255, 255, 0.6) 50%,
|
|
178
|
+
rgba(255, 255, 255, 0.25) 100%
|
|
179
|
+
);
|
|
180
|
+
transform: translateX(-100%);
|
|
181
|
+
animation: ibis-shimmer 2s infinite;
|
|
182
|
+
border-radius: inherit;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@keyframes ibis-shimmer {
|
|
186
|
+
0% {
|
|
187
|
+
transform: translateX(-100%);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
100% {
|
|
191
|
+
transform: translateX(100%);
|
|
192
|
+
}
|
|
193
|
+
}
|