@spaethtech/svelte-ui 0.15.1-dev.71.e357f8b → 0.15.1-dev.72.768dcbb
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/package.json
CHANGED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
/**
|
|
3
|
-
* ButtonDropdown — a split-button compound built from Button + Menu.
|
|
4
|
-
*
|
|
5
|
-
* Same prop surface as Button (variant, size, icon, text, children,
|
|
6
|
-
* disabled, onclick, …); when `items` is empty/absent it renders
|
|
7
|
-
* identically to a single Button. With items, it splits into a primary
|
|
8
|
-
* half (the consumer's button) and a secondary chevron half that opens
|
|
9
|
-
* a Menu anchored to the chevron.
|
|
10
|
-
*
|
|
11
|
-
* Compound rule: nothing in this file builds primitives — it composes
|
|
12
|
-
* Button + Menu. The split visual is enforced by overriding the two
|
|
13
|
-
* halves' rounded corners + adjacent border via the {class} prop both
|
|
14
|
-
* Buttons already accept; the outer wrapper carries the shape so a
|
|
15
|
-
* consumer-applied shadow (e.g. `class="shadow-md"`) lands on the
|
|
16
|
-
* combined silhouette rather than splitting at the seam between the
|
|
17
|
-
* two halves.
|
|
18
|
-
*/
|
|
19
|
-
-->
|
|
20
|
-
<script lang="ts">
|
|
21
|
-
import ChevronDown from "~icons/mdi/chevron-down";
|
|
22
|
-
import Button from "./Button.svelte";
|
|
23
|
-
import Menu from "./Menu.svelte";
|
|
24
|
-
import type { Variant } from "../types/variants.js";
|
|
25
|
-
import type { Size } from "../types/sizes.js";
|
|
26
|
-
import type { Responsive } from "../types/responsive.js";
|
|
27
|
-
import type { Snippet } from "svelte";
|
|
28
|
-
import type { MenuItem } from "../data/table/types.js";
|
|
29
|
-
|
|
30
|
-
// Mirrors Button's button-flavour Props (the anchor-flavour `href` is
|
|
31
|
-
// intentionally not on offer here — a split-button's two halves can't
|
|
32
|
-
// both be a single navigation target). Adds `items`.
|
|
33
|
-
interface Props {
|
|
34
|
-
/** Icon slot for the primary half — same contract as Button.icon. */
|
|
35
|
-
icon?: Snippet;
|
|
36
|
-
text?: string;
|
|
37
|
-
variant?: Variant;
|
|
38
|
-
size?: Responsive<Size>;
|
|
39
|
-
children?: Snippet;
|
|
40
|
-
disabled?: boolean;
|
|
41
|
-
type?: "button" | "submit" | "reset";
|
|
42
|
-
title?: string;
|
|
43
|
-
/** Append-extra classes — applied to the OUTER wrapper so consumer
|
|
44
|
-
* styling (margin, shadow, alignment) targets the combined shape
|
|
45
|
-
* rather than just one half. */
|
|
46
|
-
class?: string;
|
|
47
|
-
onclick?: (event: MouseEvent) => void;
|
|
48
|
-
/** Menu items shown when the chevron is clicked. Empty / absent →
|
|
49
|
-
* the component degrades gracefully to a plain Button. */
|
|
50
|
-
items?: MenuItem[];
|
|
51
|
-
/** Menu placement passed through to `<Menu>`. Defaults match the
|
|
52
|
-
* ActionBar split-button convention: opens below, right-aligned. */
|
|
53
|
-
menuSide?: "top" | "bottom" | "left" | "right";
|
|
54
|
-
menuAlign?: "start" | "center" | "end";
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let {
|
|
58
|
-
icon,
|
|
59
|
-
text,
|
|
60
|
-
variant = "secondary",
|
|
61
|
-
size = "md",
|
|
62
|
-
children,
|
|
63
|
-
disabled = false,
|
|
64
|
-
type = "button",
|
|
65
|
-
title,
|
|
66
|
-
class: additionalClass = "",
|
|
67
|
-
onclick,
|
|
68
|
-
items,
|
|
69
|
-
menuSide = "bottom",
|
|
70
|
-
menuAlign = "end",
|
|
71
|
-
}: Props = $props();
|
|
72
|
-
|
|
73
|
-
// No items → degrade to a plain Button with the exact same prop
|
|
74
|
-
// surface. Keeps `<ButtonDropdown {variant} {size} text="…" />`
|
|
75
|
-
// usable as a drop-in for sites that may or may not declare items
|
|
76
|
-
// dynamically.
|
|
77
|
-
const hasItems = $derived(!!items && items.length > 0);
|
|
78
|
-
|
|
79
|
-
// Chevron-half state. `chevronEl` is what Menu anchors against; the
|
|
80
|
-
// element gets bound through Button's existing `bind:element` prop so
|
|
81
|
-
// we never poke at the DOM ourselves.
|
|
82
|
-
let menuOpen = $state(false);
|
|
83
|
-
let chevronEl = $state<HTMLButtonElement | HTMLAnchorElement | undefined>(undefined);
|
|
84
|
-
|
|
85
|
-
// Class overrides applied via Button's {class} pass-through. The
|
|
86
|
-
// outer wrapper is `inline-flex` and the two halves abut; we strip
|
|
87
|
-
// the inner corners + the primary's right border so the seam reads
|
|
88
|
-
// as a single divider rather than two stacked borders.
|
|
89
|
-
const primaryHalfClass = "rounded-r-none border-r-0";
|
|
90
|
-
const secondaryHalfClass = "rounded-l-none px-2";
|
|
91
|
-
</script>
|
|
92
|
-
|
|
93
|
-
{#if hasItems}
|
|
94
|
-
<span class="inline-flex {additionalClass}">
|
|
95
|
-
<Button
|
|
96
|
-
{icon}
|
|
97
|
-
{text}
|
|
98
|
-
{children}
|
|
99
|
-
{variant}
|
|
100
|
-
{size}
|
|
101
|
-
{disabled}
|
|
102
|
-
{type}
|
|
103
|
-
{title}
|
|
104
|
-
{onclick}
|
|
105
|
-
class={primaryHalfClass}
|
|
106
|
-
/>
|
|
107
|
-
<Button
|
|
108
|
-
{variant}
|
|
109
|
-
{size}
|
|
110
|
-
{disabled}
|
|
111
|
-
type="button"
|
|
112
|
-
title="More actions"
|
|
113
|
-
aria-haspopup="menu"
|
|
114
|
-
aria-expanded={menuOpen}
|
|
115
|
-
onclick={() => (menuOpen = !menuOpen)}
|
|
116
|
-
bind:element={chevronEl}
|
|
117
|
-
class={secondaryHalfClass}
|
|
118
|
-
icon={chevronIcon}
|
|
119
|
-
/>
|
|
120
|
-
</span>
|
|
121
|
-
<Menu
|
|
122
|
-
anchor={chevronEl as HTMLElement | undefined}
|
|
123
|
-
bind:open={menuOpen}
|
|
124
|
-
items={items!}
|
|
125
|
-
side={menuSide}
|
|
126
|
-
align={menuAlign}
|
|
127
|
-
/>
|
|
128
|
-
{:else}
|
|
129
|
-
<Button
|
|
130
|
-
{icon}
|
|
131
|
-
{text}
|
|
132
|
-
{children}
|
|
133
|
-
{variant}
|
|
134
|
-
{size}
|
|
135
|
-
{disabled}
|
|
136
|
-
{type}
|
|
137
|
-
{title}
|
|
138
|
-
{onclick}
|
|
139
|
-
class={additionalClass}
|
|
140
|
-
/>
|
|
141
|
-
{/if}
|
|
142
|
-
|
|
143
|
-
{#snippet chevronIcon()}
|
|
144
|
-
<ChevronDown />
|
|
145
|
-
{/snippet}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { Variant } from "../types/variants.js";
|
|
2
|
-
import type { Size } from "../types/sizes.js";
|
|
3
|
-
import type { Responsive } from "../types/responsive.js";
|
|
4
|
-
import type { Snippet } from "svelte";
|
|
5
|
-
import type { MenuItem } from "../data/table/types.js";
|
|
6
|
-
interface Props {
|
|
7
|
-
/** Icon slot for the primary half — same contract as Button.icon. */
|
|
8
|
-
icon?: Snippet;
|
|
9
|
-
text?: string;
|
|
10
|
-
variant?: Variant;
|
|
11
|
-
size?: Responsive<Size>;
|
|
12
|
-
children?: Snippet;
|
|
13
|
-
disabled?: boolean;
|
|
14
|
-
type?: "button" | "submit" | "reset";
|
|
15
|
-
title?: string;
|
|
16
|
-
/** Append-extra classes — applied to the OUTER wrapper so consumer
|
|
17
|
-
* styling (margin, shadow, alignment) targets the combined shape
|
|
18
|
-
* rather than just one half. */
|
|
19
|
-
class?: string;
|
|
20
|
-
onclick?: (event: MouseEvent) => void;
|
|
21
|
-
/** Menu items shown when the chevron is clicked. Empty / absent →
|
|
22
|
-
* the component degrades gracefully to a plain Button. */
|
|
23
|
-
items?: MenuItem[];
|
|
24
|
-
/** Menu placement passed through to `<Menu>`. Defaults match the
|
|
25
|
-
* ActionBar split-button convention: opens below, right-aligned. */
|
|
26
|
-
menuSide?: "top" | "bottom" | "left" | "right";
|
|
27
|
-
menuAlign?: "start" | "center" | "end";
|
|
28
|
-
}
|
|
29
|
-
declare const ButtonDropdown: import("svelte").Component<Props, {}, "">;
|
|
30
|
-
type ButtonDropdown = ReturnType<typeof ButtonDropdown>;
|
|
31
|
-
export default ButtonDropdown;
|