@mystravil/hardpoint 0.2.0 → 0.3.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/CHANGELOG.md +51 -38
- package/LICENSE +25 -25
- package/README.md +67 -64
- package/dist/base.css +625 -625
- package/dist/components/AppShell.svelte +698 -698
- package/dist/components/Button.svelte +221 -174
- package/dist/components/Button.svelte.d.ts +18 -2
- package/dist/components/Checkbox.svelte +235 -235
- package/dist/components/CheckboxGroup.svelte +207 -207
- package/dist/components/Combobox.svelte +901 -901
- package/dist/components/Dialog.svelte +359 -359
- package/dist/components/Disclosure.svelte +201 -201
- package/dist/components/EmptyState.svelte +88 -88
- package/dist/components/ErrorState.svelte +135 -135
- package/dist/components/ImageViewer.svelte +764 -764
- package/dist/components/KeyValueList.svelte +114 -114
- package/dist/components/ListDetail.svelte +218 -218
- package/dist/components/LoadRegion.svelte +219 -219
- package/dist/components/MediaFrame.svelte +110 -110
- package/dist/components/MediaImage.svelte +256 -256
- package/dist/components/Menu.svelte +275 -258
- package/dist/components/MenuCheckboxItem.svelte +119 -119
- package/dist/components/MenuGroup.svelte +50 -50
- package/dist/components/MenuItem.svelte +94 -94
- package/dist/components/MenuRadioGroup.svelte +62 -62
- package/dist/components/MenuRadioItem.svelte +110 -110
- package/dist/components/MenuSeparator.svelte +28 -28
- package/dist/components/Meter.svelte +283 -283
- package/dist/components/NativeSelect.svelte +135 -135
- package/dist/components/Notice.svelte +262 -262
- package/dist/components/Popover.svelte +222 -222
- package/dist/components/Progress.svelte +157 -157
- package/dist/components/RadioGroup.svelte +440 -440
- package/dist/components/Select.svelte +471 -471
- package/dist/components/Skeleton.svelte +149 -149
- package/dist/components/Spinner.svelte +118 -118
- package/dist/components/Stat.svelte +253 -253
- package/dist/components/Steps.svelte +189 -189
- package/dist/components/Switch.svelte +222 -222
- package/dist/components/Table.svelte +504 -504
- package/dist/components/Tabs.svelte +246 -246
- package/dist/components/Tag.svelte +40 -40
- package/dist/components/TextArea.svelte +272 -272
- package/dist/components/TextField.svelte +396 -256
- package/dist/components/TextField.svelte.d.ts +16 -1
- package/dist/components/Timeline.svelte +156 -156
- package/dist/components/Toaster.svelte +411 -411
- package/dist/components/Tooltip.svelte +200 -200
- package/dist/components/TooltipGroup.svelte +46 -46
- package/dist/components/internal/Scrim.svelte +52 -52
- package/dist/components/internal/Sheet.svelte +263 -263
- package/dist/fonts.css +71 -71
- package/dist/tokens.css +283 -283
- package/package.json +81 -76
|
@@ -1,119 +1,119 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Attributes and handlers not listed here go to the item element (Bits UI
|
|
7
|
-
* `DropdownMenu.CheckboxItem`), among them `disabled`, `onCheckedChange`,
|
|
8
|
-
* `onSelect` and `closeOnSelect` (default true; pass false to keep the
|
|
9
|
-
* menu open, so the change shows).
|
|
10
|
-
*/
|
|
11
|
-
export type MenuCheckboxItemProps = Omit<
|
|
12
|
-
BitsDropdownMenu.CheckboxItemProps,
|
|
13
|
-
'child' | 'children' | 'indeterminate' | 'onIndeterminateChange' | 'value'
|
|
14
|
-
> & {
|
|
15
|
-
/** The label, as written (never caps). */
|
|
16
|
-
children: Snippet;
|
|
17
|
-
};
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<script lang="ts">
|
|
21
|
-
import { DropdownMenu } from 'bits-ui';
|
|
22
|
-
|
|
23
|
-
let {
|
|
24
|
-
checked = $bindable(false),
|
|
25
|
-
ref = $bindable(null),
|
|
26
|
-
class: className,
|
|
27
|
-
children,
|
|
28
|
-
...rest
|
|
29
|
-
}: MenuCheckboxItemProps = $props();
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
<!--
|
|
33
|
-
A Bits UI checkbox item, role="menuitemcheckbox", with aria-checked and
|
|
34
|
-
data-state (checked, unchecked). A press, Enter or Space toggles it.
|
|
35
|
-
-->
|
|
36
|
-
<DropdownMenu.CheckboxItem bind:checked bind:ref {...rest}>
|
|
37
|
-
{#snippet child({ props })}
|
|
38
|
-
<div {...props} class={['hp-menu-checkbox-item', className]}>
|
|
39
|
-
<span class="hp-menu-box" aria-hidden="true">
|
|
40
|
-
<svg class="hp-menu-check" viewBox="0 0 12 12"><path d="M1.5 6.5l3 3 6-6" /></svg>
|
|
41
|
-
</span>
|
|
42
|
-
<span class="hp-menu-item-label">{@render children()}</span>
|
|
43
|
-
</div>
|
|
44
|
-
{/snippet}
|
|
45
|
-
</DropdownMenu.CheckboxItem>
|
|
46
|
-
|
|
47
|
-
<style>
|
|
48
|
-
/* The row: the same as MenuItem's. Only the mark fades (below). */
|
|
49
|
-
.hp-menu-checkbox-item {
|
|
50
|
-
display: flex;
|
|
51
|
-
align-items: center;
|
|
52
|
-
gap: var(--space-3);
|
|
53
|
-
box-sizing: border-box;
|
|
54
|
-
min-height: var(--control-height);
|
|
55
|
-
padding: var(--space-1) var(--menu-inset, var(--space-3));
|
|
56
|
-
font: var(--type-body) / 24px var(--sans);
|
|
57
|
-
overflow-wrap: anywhere;
|
|
58
|
-
cursor: pointer;
|
|
59
|
-
user-select: none;
|
|
60
|
-
touch-action: manipulation;
|
|
61
|
-
-webkit-tap-highlight-color: transparent;
|
|
62
|
-
outline: none;
|
|
63
|
-
}
|
|
64
|
-
.hp-menu-item-label {
|
|
65
|
-
flex: 1 1 auto;
|
|
66
|
-
min-width: 0;
|
|
67
|
-
}
|
|
68
|
-
.hp-menu-checkbox-item[data-highlighted] {
|
|
69
|
-
background: var(--surface-hover);
|
|
70
|
-
outline: var(--menu-contour, none);
|
|
71
|
-
outline-offset: -2px;
|
|
72
|
-
}
|
|
73
|
-
.hp-menu-checkbox-item:active:not([data-disabled]) {
|
|
74
|
-
background: var(--surface-raised);
|
|
75
|
-
}
|
|
76
|
-
.hp-menu-checkbox-item[data-disabled] {
|
|
77
|
-
color: var(--muted);
|
|
78
|
-
cursor: not-allowed;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/* Checkbox's black box with a 3:1 boundary. Checked, the edge and the
|
|
82
|
-
mark turn titanium and the box stays black: selection is never a fill.
|
|
83
|
-
The row's tint is the hover feedback. */
|
|
84
|
-
.hp-menu-box {
|
|
85
|
-
flex: none;
|
|
86
|
-
display: grid;
|
|
87
|
-
place-items: center;
|
|
88
|
-
box-sizing: border-box;
|
|
89
|
-
width: 20px;
|
|
90
|
-
height: 20px;
|
|
91
|
-
border: 1px solid var(--border-control);
|
|
92
|
-
background: var(--canvas);
|
|
93
|
-
color: var(--accent);
|
|
94
|
-
}
|
|
95
|
-
.hp-menu-checkbox-item[data-state='checked'] .hp-menu-box {
|
|
96
|
-
border-color: var(--accent);
|
|
97
|
-
}
|
|
98
|
-
.hp-menu-checkbox-item[data-disabled] .hp-menu-box {
|
|
99
|
-
border-color: var(--border);
|
|
100
|
-
color: var(--muted);
|
|
101
|
-
}
|
|
102
|
-
/* The check is always there, at opacity 0 until the item is checked.
|
|
103
|
-
Checking fades it in from 0 over --dur-mark (BRIEF, short motion);
|
|
104
|
-
unchecking takes it away at once. A CSS transition never runs on an
|
|
105
|
-
element's first style, so a menu that opens shows its marks at once.
|
|
106
|
-
0ms is a snap. Opacity only, so reduced motion keeps it. */
|
|
107
|
-
.hp-menu-check {
|
|
108
|
-
width: 12px;
|
|
109
|
-
height: 12px;
|
|
110
|
-
fill: none;
|
|
111
|
-
stroke: currentColor;
|
|
112
|
-
stroke-width: 2px;
|
|
113
|
-
opacity: 0;
|
|
114
|
-
}
|
|
115
|
-
.hp-menu-checkbox-item[data-state='checked'] .hp-menu-check {
|
|
116
|
-
opacity: 1;
|
|
117
|
-
transition: opacity var(--dur-mark) var(--settle);
|
|
118
|
-
}
|
|
119
|
-
</style>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Attributes and handlers not listed here go to the item element (Bits UI
|
|
7
|
+
* `DropdownMenu.CheckboxItem`), among them `disabled`, `onCheckedChange`,
|
|
8
|
+
* `onSelect` and `closeOnSelect` (default true; pass false to keep the
|
|
9
|
+
* menu open, so the change shows).
|
|
10
|
+
*/
|
|
11
|
+
export type MenuCheckboxItemProps = Omit<
|
|
12
|
+
BitsDropdownMenu.CheckboxItemProps,
|
|
13
|
+
'child' | 'children' | 'indeterminate' | 'onIndeterminateChange' | 'value'
|
|
14
|
+
> & {
|
|
15
|
+
/** The label, as written (never caps). */
|
|
16
|
+
children: Snippet;
|
|
17
|
+
};
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import { DropdownMenu } from 'bits-ui';
|
|
22
|
+
|
|
23
|
+
let {
|
|
24
|
+
checked = $bindable(false),
|
|
25
|
+
ref = $bindable(null),
|
|
26
|
+
class: className,
|
|
27
|
+
children,
|
|
28
|
+
...rest
|
|
29
|
+
}: MenuCheckboxItemProps = $props();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<!--
|
|
33
|
+
A Bits UI checkbox item, role="menuitemcheckbox", with aria-checked and
|
|
34
|
+
data-state (checked, unchecked). A press, Enter or Space toggles it.
|
|
35
|
+
-->
|
|
36
|
+
<DropdownMenu.CheckboxItem bind:checked bind:ref {...rest}>
|
|
37
|
+
{#snippet child({ props })}
|
|
38
|
+
<div {...props} class={['hp-menu-checkbox-item', className]}>
|
|
39
|
+
<span class="hp-menu-box" aria-hidden="true">
|
|
40
|
+
<svg class="hp-menu-check" viewBox="0 0 12 12"><path d="M1.5 6.5l3 3 6-6" /></svg>
|
|
41
|
+
</span>
|
|
42
|
+
<span class="hp-menu-item-label">{@render children()}</span>
|
|
43
|
+
</div>
|
|
44
|
+
{/snippet}
|
|
45
|
+
</DropdownMenu.CheckboxItem>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
/* The row: the same as MenuItem's. Only the mark fades (below). */
|
|
49
|
+
.hp-menu-checkbox-item {
|
|
50
|
+
display: flex;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: var(--space-3);
|
|
53
|
+
box-sizing: border-box;
|
|
54
|
+
min-height: var(--control-height);
|
|
55
|
+
padding: var(--space-1) var(--menu-inset, var(--space-3));
|
|
56
|
+
font: var(--type-body) / 24px var(--sans);
|
|
57
|
+
overflow-wrap: anywhere;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
user-select: none;
|
|
60
|
+
touch-action: manipulation;
|
|
61
|
+
-webkit-tap-highlight-color: transparent;
|
|
62
|
+
outline: none;
|
|
63
|
+
}
|
|
64
|
+
.hp-menu-item-label {
|
|
65
|
+
flex: 1 1 auto;
|
|
66
|
+
min-width: 0;
|
|
67
|
+
}
|
|
68
|
+
.hp-menu-checkbox-item[data-highlighted] {
|
|
69
|
+
background: var(--surface-hover);
|
|
70
|
+
outline: var(--menu-contour, none);
|
|
71
|
+
outline-offset: -2px;
|
|
72
|
+
}
|
|
73
|
+
.hp-menu-checkbox-item:active:not([data-disabled]) {
|
|
74
|
+
background: var(--surface-raised);
|
|
75
|
+
}
|
|
76
|
+
.hp-menu-checkbox-item[data-disabled] {
|
|
77
|
+
color: var(--muted);
|
|
78
|
+
cursor: not-allowed;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* Checkbox's black box with a 3:1 boundary. Checked, the edge and the
|
|
82
|
+
mark turn titanium and the box stays black: selection is never a fill.
|
|
83
|
+
The row's tint is the hover feedback. */
|
|
84
|
+
.hp-menu-box {
|
|
85
|
+
flex: none;
|
|
86
|
+
display: grid;
|
|
87
|
+
place-items: center;
|
|
88
|
+
box-sizing: border-box;
|
|
89
|
+
width: 20px;
|
|
90
|
+
height: 20px;
|
|
91
|
+
border: 1px solid var(--border-control);
|
|
92
|
+
background: var(--canvas);
|
|
93
|
+
color: var(--accent);
|
|
94
|
+
}
|
|
95
|
+
.hp-menu-checkbox-item[data-state='checked'] .hp-menu-box {
|
|
96
|
+
border-color: var(--accent);
|
|
97
|
+
}
|
|
98
|
+
.hp-menu-checkbox-item[data-disabled] .hp-menu-box {
|
|
99
|
+
border-color: var(--border);
|
|
100
|
+
color: var(--muted);
|
|
101
|
+
}
|
|
102
|
+
/* The check is always there, at opacity 0 until the item is checked.
|
|
103
|
+
Checking fades it in from 0 over --dur-mark (BRIEF, short motion);
|
|
104
|
+
unchecking takes it away at once. A CSS transition never runs on an
|
|
105
|
+
element's first style, so a menu that opens shows its marks at once.
|
|
106
|
+
0ms is a snap. Opacity only, so reduced motion keeps it. */
|
|
107
|
+
.hp-menu-check {
|
|
108
|
+
width: 12px;
|
|
109
|
+
height: 12px;
|
|
110
|
+
fill: none;
|
|
111
|
+
stroke: currentColor;
|
|
112
|
+
stroke-width: 2px;
|
|
113
|
+
opacity: 0;
|
|
114
|
+
}
|
|
115
|
+
.hp-menu-checkbox-item[data-state='checked'] .hp-menu-check {
|
|
116
|
+
opacity: 1;
|
|
117
|
+
transition: opacity var(--dur-mark) var(--settle);
|
|
118
|
+
}
|
|
119
|
+
</style>
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
-
|
|
5
|
-
/** Attributes not listed here go to the group element (Bits UI `DropdownMenu.Group`). */
|
|
6
|
-
export type MenuGroupProps = Omit<BitsDropdownMenu.GroupProps, 'child' | 'children'> & {
|
|
7
|
-
/**
|
|
8
|
-
* The caps heading over the items, and the group's accessible name. A
|
|
9
|
-
* fixed string the app defines, set in caps; never user data.
|
|
10
|
-
*/
|
|
11
|
-
label?: string;
|
|
12
|
-
/** The items. */
|
|
13
|
-
children: Snippet;
|
|
14
|
-
};
|
|
15
|
-
</script>
|
|
16
|
-
|
|
17
|
-
<script lang="ts">
|
|
18
|
-
import { DropdownMenu } from 'bits-ui';
|
|
19
|
-
|
|
20
|
-
let { label, ref = $bindable(null), class: className, children, ...rest }: MenuGroupProps = $props();
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<!--
|
|
24
|
-
A Bits UI group, role="group", named by its heading through
|
|
25
|
-
aria-labelledby. Separate groups with a MenuSeparator.
|
|
26
|
-
-->
|
|
27
|
-
<DropdownMenu.Group bind:ref {...rest}>
|
|
28
|
-
{#snippet child({ props })}
|
|
29
|
-
<div {...props} class={['hp-menu-group', className]}>
|
|
30
|
-
{#if label}
|
|
31
|
-
<DropdownMenu.GroupHeading>
|
|
32
|
-
{#snippet child({ props: headingProps })}
|
|
33
|
-
<div {...headingProps} class="hp-menu-group-heading hp-label">{label}</div>
|
|
34
|
-
{/snippet}
|
|
35
|
-
</DropdownMenu.GroupHeading>
|
|
36
|
-
{/if}
|
|
37
|
-
{@render children()}
|
|
38
|
-
</div>
|
|
39
|
-
{/snippet}
|
|
40
|
-
</DropdownMenu.Group>
|
|
41
|
-
|
|
42
|
-
<style>
|
|
43
|
-
/* A muted caps label over the items, its text on the items' text edge.
|
|
44
|
-
The same heading as MenuRadioGroup's. */
|
|
45
|
-
.hp-menu-group-heading {
|
|
46
|
-
padding: var(--space-2) var(--menu-inset, var(--space-3)) var(--space-1);
|
|
47
|
-
color: var(--muted);
|
|
48
|
-
user-select: none;
|
|
49
|
-
}
|
|
50
|
-
</style>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
/** Attributes not listed here go to the group element (Bits UI `DropdownMenu.Group`). */
|
|
6
|
+
export type MenuGroupProps = Omit<BitsDropdownMenu.GroupProps, 'child' | 'children'> & {
|
|
7
|
+
/**
|
|
8
|
+
* The caps heading over the items, and the group's accessible name. A
|
|
9
|
+
* fixed string the app defines, set in caps; never user data.
|
|
10
|
+
*/
|
|
11
|
+
label?: string;
|
|
12
|
+
/** The items. */
|
|
13
|
+
children: Snippet;
|
|
14
|
+
};
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { DropdownMenu } from 'bits-ui';
|
|
19
|
+
|
|
20
|
+
let { label, ref = $bindable(null), class: className, children, ...rest }: MenuGroupProps = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<!--
|
|
24
|
+
A Bits UI group, role="group", named by its heading through
|
|
25
|
+
aria-labelledby. Separate groups with a MenuSeparator.
|
|
26
|
+
-->
|
|
27
|
+
<DropdownMenu.Group bind:ref {...rest}>
|
|
28
|
+
{#snippet child({ props })}
|
|
29
|
+
<div {...props} class={['hp-menu-group', className]}>
|
|
30
|
+
{#if label}
|
|
31
|
+
<DropdownMenu.GroupHeading>
|
|
32
|
+
{#snippet child({ props: headingProps })}
|
|
33
|
+
<div {...headingProps} class="hp-menu-group-heading hp-label">{label}</div>
|
|
34
|
+
{/snippet}
|
|
35
|
+
</DropdownMenu.GroupHeading>
|
|
36
|
+
{/if}
|
|
37
|
+
{@render children()}
|
|
38
|
+
</div>
|
|
39
|
+
{/snippet}
|
|
40
|
+
</DropdownMenu.Group>
|
|
41
|
+
|
|
42
|
+
<style>
|
|
43
|
+
/* A muted caps label over the items, its text on the items' text edge.
|
|
44
|
+
The same heading as MenuRadioGroup's. */
|
|
45
|
+
.hp-menu-group-heading {
|
|
46
|
+
padding: var(--space-2) var(--menu-inset, var(--space-3)) var(--space-1);
|
|
47
|
+
color: var(--muted);
|
|
48
|
+
user-select: none;
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
@@ -1,94 +1,94 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
-
|
|
5
|
-
export type MenuItemVariant = 'default' | 'danger';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Attributes and handlers not listed here go to the item element (Bits UI
|
|
9
|
-
* `DropdownMenu.Item`), among them `disabled`, `onSelect` (call
|
|
10
|
-
* `preventDefault()` on its event to keep the menu open), `closeOnSelect`
|
|
11
|
-
* (default true) and `textValue`. Typeahead matches the label's text:
|
|
12
|
-
* Bits UI 2.20.6 declares `textValue` but does not read it yet.
|
|
13
|
-
*/
|
|
14
|
-
export type MenuItemProps = Omit<BitsDropdownMenu.ItemProps, 'child' | 'children'> & {
|
|
15
|
-
/** `danger` (status red) for an action that destroys or removes something. */
|
|
16
|
-
variant?: MenuItemVariant;
|
|
17
|
-
/** The label, as written (never caps). */
|
|
18
|
-
children: Snippet;
|
|
19
|
-
};
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<script lang="ts">
|
|
23
|
-
import { DropdownMenu } from 'bits-ui';
|
|
24
|
-
|
|
25
|
-
let {
|
|
26
|
-
variant = 'default',
|
|
27
|
-
ref = $bindable(null),
|
|
28
|
-
class: className,
|
|
29
|
-
children,
|
|
30
|
-
...rest
|
|
31
|
-
}: MenuItemProps = $props();
|
|
32
|
-
</script>
|
|
33
|
-
|
|
34
|
-
<!--
|
|
35
|
-
A Bits UI menu item, role="menuitem", with Bits UI's data-highlighted,
|
|
36
|
-
data-disabled and aria-disabled. A press, Enter or Space runs `onSelect`
|
|
37
|
-
and closes the menu.
|
|
38
|
-
-->
|
|
39
|
-
<DropdownMenu.Item bind:ref {...rest}>
|
|
40
|
-
{#snippet child({ props })}
|
|
41
|
-
<div {...props} class={['hp-menu-item', className]} data-variant={variant}>
|
|
42
|
-
<span class="hp-menu-item-label">{@render children()}</span>
|
|
43
|
-
</div>
|
|
44
|
-
{/snippet}
|
|
45
|
-
</DropdownMenu.Item>
|
|
46
|
-
|
|
47
|
-
<style>
|
|
48
|
-
/* A Geist row, sentence case: 36px on fine pointers, 44px on coarse.
|
|
49
|
-
The label is one flex item, so inline markup inside it stays inline.
|
|
50
|
-
Highlight moves snap, so nothing on a row transitions (BRIEF, motion
|
|
51
|
-
rule 3). Same row as MenuCheckboxItem and MenuRadioItem. */
|
|
52
|
-
.hp-menu-item {
|
|
53
|
-
display: flex;
|
|
54
|
-
align-items: center;
|
|
55
|
-
gap: var(--space-3);
|
|
56
|
-
box-sizing: border-box;
|
|
57
|
-
min-height: var(--control-height);
|
|
58
|
-
padding: var(--space-1) var(--menu-inset, var(--space-3));
|
|
59
|
-
font: var(--type-body) / 24px var(--sans);
|
|
60
|
-
overflow-wrap: anywhere;
|
|
61
|
-
cursor: pointer;
|
|
62
|
-
user-select: none;
|
|
63
|
-
touch-action: manipulation;
|
|
64
|
-
-webkit-tap-highlight-color: transparent;
|
|
65
|
-
outline: none;
|
|
66
|
-
}
|
|
67
|
-
.hp-menu-item-label {
|
|
68
|
-
flex: 1 1 auto;
|
|
69
|
-
min-width: 0;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/* Highlighted, by keys or a pointer: the hover tint. A highlight the keys
|
|
73
|
-
moved also draws the focus contour inside the row (Menu sets
|
|
74
|
-
--menu-contour). */
|
|
75
|
-
.hp-menu-item[data-highlighted] {
|
|
76
|
-
background: var(--surface-hover);
|
|
77
|
-
outline: var(--menu-contour, none);
|
|
78
|
-
outline-offset: -2px;
|
|
79
|
-
}
|
|
80
|
-
/* Press: one step past the tint, so it reads on a phone too. */
|
|
81
|
-
.hp-menu-item:active:not([data-disabled]) {
|
|
82
|
-
background: var(--surface-raised);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.hp-menu-item[data-variant='danger'] {
|
|
86
|
-
color: var(--danger);
|
|
87
|
-
}
|
|
88
|
-
/* Disabled: muted, even a danger item; keys skip it and a pointer does
|
|
89
|
-
not highlight it. */
|
|
90
|
-
.hp-menu-item[data-disabled] {
|
|
91
|
-
color: var(--muted);
|
|
92
|
-
cursor: not-allowed;
|
|
93
|
-
}
|
|
94
|
-
</style>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
export type MenuItemVariant = 'default' | 'danger';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Attributes and handlers not listed here go to the item element (Bits UI
|
|
9
|
+
* `DropdownMenu.Item`), among them `disabled`, `onSelect` (call
|
|
10
|
+
* `preventDefault()` on its event to keep the menu open), `closeOnSelect`
|
|
11
|
+
* (default true) and `textValue`. Typeahead matches the label's text:
|
|
12
|
+
* Bits UI 2.20.6 declares `textValue` but does not read it yet.
|
|
13
|
+
*/
|
|
14
|
+
export type MenuItemProps = Omit<BitsDropdownMenu.ItemProps, 'child' | 'children'> & {
|
|
15
|
+
/** `danger` (status red) for an action that destroys or removes something. */
|
|
16
|
+
variant?: MenuItemVariant;
|
|
17
|
+
/** The label, as written (never caps). */
|
|
18
|
+
children: Snippet;
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { DropdownMenu } from 'bits-ui';
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
variant = 'default',
|
|
27
|
+
ref = $bindable(null),
|
|
28
|
+
class: className,
|
|
29
|
+
children,
|
|
30
|
+
...rest
|
|
31
|
+
}: MenuItemProps = $props();
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<!--
|
|
35
|
+
A Bits UI menu item, role="menuitem", with Bits UI's data-highlighted,
|
|
36
|
+
data-disabled and aria-disabled. A press, Enter or Space runs `onSelect`
|
|
37
|
+
and closes the menu.
|
|
38
|
+
-->
|
|
39
|
+
<DropdownMenu.Item bind:ref {...rest}>
|
|
40
|
+
{#snippet child({ props })}
|
|
41
|
+
<div {...props} class={['hp-menu-item', className]} data-variant={variant}>
|
|
42
|
+
<span class="hp-menu-item-label">{@render children()}</span>
|
|
43
|
+
</div>
|
|
44
|
+
{/snippet}
|
|
45
|
+
</DropdownMenu.Item>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
/* A Geist row, sentence case: 36px on fine pointers, 44px on coarse.
|
|
49
|
+
The label is one flex item, so inline markup inside it stays inline.
|
|
50
|
+
Highlight moves snap, so nothing on a row transitions (BRIEF, motion
|
|
51
|
+
rule 3). Same row as MenuCheckboxItem and MenuRadioItem. */
|
|
52
|
+
.hp-menu-item {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: center;
|
|
55
|
+
gap: var(--space-3);
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
min-height: var(--control-height);
|
|
58
|
+
padding: var(--space-1) var(--menu-inset, var(--space-3));
|
|
59
|
+
font: var(--type-body) / 24px var(--sans);
|
|
60
|
+
overflow-wrap: anywhere;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
user-select: none;
|
|
63
|
+
touch-action: manipulation;
|
|
64
|
+
-webkit-tap-highlight-color: transparent;
|
|
65
|
+
outline: none;
|
|
66
|
+
}
|
|
67
|
+
.hp-menu-item-label {
|
|
68
|
+
flex: 1 1 auto;
|
|
69
|
+
min-width: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Highlighted, by keys or a pointer: the hover tint. A highlight the keys
|
|
73
|
+
moved also draws the focus contour inside the row (Menu sets
|
|
74
|
+
--menu-contour). */
|
|
75
|
+
.hp-menu-item[data-highlighted] {
|
|
76
|
+
background: var(--surface-hover);
|
|
77
|
+
outline: var(--menu-contour, none);
|
|
78
|
+
outline-offset: -2px;
|
|
79
|
+
}
|
|
80
|
+
/* Press: one step past the tint, so it reads on a phone too. */
|
|
81
|
+
.hp-menu-item:active:not([data-disabled]) {
|
|
82
|
+
background: var(--surface-raised);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.hp-menu-item[data-variant='danger'] {
|
|
86
|
+
color: var(--danger);
|
|
87
|
+
}
|
|
88
|
+
/* Disabled: muted, even a danger item; keys skip it and a pointer does
|
|
89
|
+
not highlight it. */
|
|
90
|
+
.hp-menu-item[data-disabled] {
|
|
91
|
+
color: var(--muted);
|
|
92
|
+
cursor: not-allowed;
|
|
93
|
+
}
|
|
94
|
+
</style>
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
<script lang="ts" module>
|
|
2
|
-
import type { Snippet } from 'svelte';
|
|
3
|
-
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Attributes and handlers not listed here go to the group element (Bits
|
|
7
|
-
* UI `DropdownMenu.RadioGroup`), among them `onValueChange`.
|
|
8
|
-
*/
|
|
9
|
-
export type MenuRadioGroupProps = Omit<BitsDropdownMenu.RadioGroupProps, 'child' | 'children'> & {
|
|
10
|
-
/** The chosen MenuRadioItem's `value`; `''` for none. */
|
|
11
|
-
value?: string;
|
|
12
|
-
/**
|
|
13
|
-
* The caps heading over the items, and the group's accessible name. A
|
|
14
|
-
* fixed string the app defines, set in caps; never user data.
|
|
15
|
-
*/
|
|
16
|
-
label?: string;
|
|
17
|
-
/** The MenuRadioItems. */
|
|
18
|
-
children: Snippet;
|
|
19
|
-
};
|
|
20
|
-
</script>
|
|
21
|
-
|
|
22
|
-
<script lang="ts">
|
|
23
|
-
import { DropdownMenu } from 'bits-ui';
|
|
24
|
-
|
|
25
|
-
let {
|
|
26
|
-
value = $bindable(''),
|
|
27
|
-
label,
|
|
28
|
-
ref = $bindable(null),
|
|
29
|
-
class: className,
|
|
30
|
-
children,
|
|
31
|
-
...rest
|
|
32
|
-
}: MenuRadioGroupProps = $props();
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<!--
|
|
36
|
-
A Bits UI radio group, role="group", named by its heading through
|
|
37
|
-
aria-labelledby. One of its MenuRadioItems is chosen at a time.
|
|
38
|
-
-->
|
|
39
|
-
<DropdownMenu.RadioGroup bind:value bind:ref {...rest}>
|
|
40
|
-
{#snippet child({ props })}
|
|
41
|
-
<div {...props} class={['hp-menu-radio-group', className]}>
|
|
42
|
-
{#if label}
|
|
43
|
-
<DropdownMenu.GroupHeading>
|
|
44
|
-
{#snippet child({ props: headingProps })}
|
|
45
|
-
<div {...headingProps} class="hp-menu-group-heading hp-label">{label}</div>
|
|
46
|
-
{/snippet}
|
|
47
|
-
</DropdownMenu.GroupHeading>
|
|
48
|
-
{/if}
|
|
49
|
-
{@render children()}
|
|
50
|
-
</div>
|
|
51
|
-
{/snippet}
|
|
52
|
-
</DropdownMenu.RadioGroup>
|
|
53
|
-
|
|
54
|
-
<style>
|
|
55
|
-
/* MenuGroup's heading: a muted caps label over the items, its text on
|
|
56
|
-
the items' text edge. */
|
|
57
|
-
.hp-menu-group-heading {
|
|
58
|
-
padding: var(--space-2) var(--menu-inset, var(--space-3)) var(--space-1);
|
|
59
|
-
color: var(--muted);
|
|
60
|
-
user-select: none;
|
|
61
|
-
}
|
|
62
|
-
</style>
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { DropdownMenu as BitsDropdownMenu } from 'bits-ui';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Attributes and handlers not listed here go to the group element (Bits
|
|
7
|
+
* UI `DropdownMenu.RadioGroup`), among them `onValueChange`.
|
|
8
|
+
*/
|
|
9
|
+
export type MenuRadioGroupProps = Omit<BitsDropdownMenu.RadioGroupProps, 'child' | 'children'> & {
|
|
10
|
+
/** The chosen MenuRadioItem's `value`; `''` for none. */
|
|
11
|
+
value?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The caps heading over the items, and the group's accessible name. A
|
|
14
|
+
* fixed string the app defines, set in caps; never user data.
|
|
15
|
+
*/
|
|
16
|
+
label?: string;
|
|
17
|
+
/** The MenuRadioItems. */
|
|
18
|
+
children: Snippet;
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { DropdownMenu } from 'bits-ui';
|
|
24
|
+
|
|
25
|
+
let {
|
|
26
|
+
value = $bindable(''),
|
|
27
|
+
label,
|
|
28
|
+
ref = $bindable(null),
|
|
29
|
+
class: className,
|
|
30
|
+
children,
|
|
31
|
+
...rest
|
|
32
|
+
}: MenuRadioGroupProps = $props();
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<!--
|
|
36
|
+
A Bits UI radio group, role="group", named by its heading through
|
|
37
|
+
aria-labelledby. One of its MenuRadioItems is chosen at a time.
|
|
38
|
+
-->
|
|
39
|
+
<DropdownMenu.RadioGroup bind:value bind:ref {...rest}>
|
|
40
|
+
{#snippet child({ props })}
|
|
41
|
+
<div {...props} class={['hp-menu-radio-group', className]}>
|
|
42
|
+
{#if label}
|
|
43
|
+
<DropdownMenu.GroupHeading>
|
|
44
|
+
{#snippet child({ props: headingProps })}
|
|
45
|
+
<div {...headingProps} class="hp-menu-group-heading hp-label">{label}</div>
|
|
46
|
+
{/snippet}
|
|
47
|
+
</DropdownMenu.GroupHeading>
|
|
48
|
+
{/if}
|
|
49
|
+
{@render children()}
|
|
50
|
+
</div>
|
|
51
|
+
{/snippet}
|
|
52
|
+
</DropdownMenu.RadioGroup>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
/* MenuGroup's heading: a muted caps label over the items, its text on
|
|
56
|
+
the items' text edge. */
|
|
57
|
+
.hp-menu-group-heading {
|
|
58
|
+
padding: var(--space-2) var(--menu-inset, var(--space-3)) var(--space-1);
|
|
59
|
+
color: var(--muted);
|
|
60
|
+
user-select: none;
|
|
61
|
+
}
|
|
62
|
+
</style>
|