lutra 0.0.13 → 0.0.15

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.
Files changed (112) hide show
  1. package/dist/data/Stat.svelte +1 -1
  2. package/dist/display/Avatar.svelte +1 -1
  3. package/dist/display/Badge.svelte +1 -1
  4. package/dist/display/Callout.svelte +3 -3
  5. package/dist/display/Code.svelte +1 -1
  6. package/dist/display/ContextTip.svelte +1 -1
  7. package/dist/display/Details.svelte +1 -1
  8. package/dist/display/Hero.svelte +1 -1
  9. package/dist/display/Icon.svelte +9 -3
  10. package/dist/display/IconButton.svelte +9 -9
  11. package/dist/display/IconButton.svelte.d.ts +0 -2
  12. package/dist/display/Image.svelte +41 -0
  13. package/dist/display/Image.svelte.d.ts +24 -0
  14. package/dist/display/Indicator.svelte +1 -1
  15. package/dist/display/Inset.svelte +18 -0
  16. package/dist/display/Inset.svelte.d.ts +17 -0
  17. package/dist/display/Popup.svelte +1 -1
  18. package/dist/display/Popup.svelte.d.ts +1 -3
  19. package/dist/display/Table.svelte +21 -0
  20. package/dist/display/Table.svelte.d.ts +23 -0
  21. package/dist/display/Tag.svelte +2 -2
  22. package/dist/display/Tooltip.svelte +1 -1
  23. package/dist/display/index.d.ts +1 -0
  24. package/dist/display/index.js +1 -0
  25. package/dist/form/Button.svelte +1 -1
  26. package/dist/form/FieldActions.svelte +26 -6
  27. package/dist/form/FieldActions.svelte.d.ts +1 -0
  28. package/dist/form/FieldContainer.svelte +4 -3
  29. package/dist/form/FieldContent.svelte +54 -16
  30. package/dist/form/FieldError.svelte +1 -1
  31. package/dist/form/FieldSection.svelte +20 -47
  32. package/dist/form/Fieldset.svelte +10 -5
  33. package/dist/form/Fieldset.svelte.d.ts +2 -0
  34. package/dist/form/Form.svelte +1 -1
  35. package/dist/form/Input.svelte +19 -40
  36. package/dist/form/Input.svelte.d.ts +2 -0
  37. package/dist/form/InputLength.svelte +1 -1
  38. package/dist/form/Label.svelte +2 -1
  39. package/dist/form/Select.svelte +1 -1
  40. package/dist/grid/Column.svelte +1 -1
  41. package/dist/grid/Grid.svelte +1 -1
  42. package/dist/grid/Row.svelte +1 -1
  43. package/dist/icons/Alert.svelte +2 -2
  44. package/dist/icons/Copy.svelte +2 -2
  45. package/dist/icons/Done.svelte +2 -2
  46. package/dist/icons/Error.svelte +2 -2
  47. package/dist/icons/Help.svelte +2 -2
  48. package/dist/icons/Hide.svelte +2 -2
  49. package/dist/icons/Info.svelte +2 -2
  50. package/dist/icons/Link.svelte +2 -2
  51. package/dist/icons/MenuBurger.svelte +3 -0
  52. package/dist/icons/MenuBurger.svelte.d.ts +23 -0
  53. package/dist/icons/MenuDots.svelte +3 -0
  54. package/dist/icons/MenuDots.svelte.d.ts +23 -0
  55. package/dist/icons/Show.svelte +2 -2
  56. package/dist/icons/Success.svelte +2 -2
  57. package/dist/icons/Warning.svelte +2 -2
  58. package/dist/layout/Layout.svelte +1 -1
  59. package/dist/layout/LayoutFooter.svelte +1 -1
  60. package/dist/layout/LayoutGrid.svelte +1 -1
  61. package/dist/layout/LayoutHeader.svelte +1 -1
  62. package/dist/layout/PageContent.svelte +1 -1
  63. package/dist/layout/Theme.svelte +7 -7
  64. package/dist/layout/UIContent.svelte +1 -1
  65. package/dist/nav/Breadcrumb.svelte +1 -1
  66. package/dist/nav/Menu.svelte +177 -161
  67. package/dist/nav/Menu.svelte.d.ts +11 -3
  68. package/dist/nav/MenuItem.svelte +122 -0
  69. package/dist/nav/MenuItem.svelte.d.ts +17 -0
  70. package/dist/nav/MenuTypes.d.ts +24 -3
  71. package/dist/nav/NavMenu.svelte +183 -0
  72. package/dist/nav/NavMenu.svelte.d.ts +18 -0
  73. package/dist/nav/TabbedContent.svelte +1 -1
  74. package/dist/nav/Tabs.svelte +8 -8
  75. package/dist/nav/index.d.ts +2 -0
  76. package/dist/nav/index.js +1 -0
  77. package/dist/style.css +36 -24
  78. package/dist/typo/Clamp.svelte +1 -1
  79. package/dist/typo/H.svelte +3 -2
  80. package/dist/typo/H.svelte.d.ts +2 -0
  81. package/dist/typo/H1.svelte +3 -3
  82. package/dist/typo/H1.svelte.d.ts +2 -0
  83. package/dist/typo/H2.svelte +3 -2
  84. package/dist/typo/H2.svelte.d.ts +2 -0
  85. package/dist/typo/H3.svelte +3 -2
  86. package/dist/typo/H3.svelte.d.ts +2 -0
  87. package/dist/typo/H4.svelte +3 -2
  88. package/dist/typo/H4.svelte.d.ts +2 -0
  89. package/dist/typo/H5.svelte +3 -2
  90. package/dist/typo/H5.svelte.d.ts +2 -0
  91. package/dist/typo/H6.svelte +3 -2
  92. package/dist/typo/H6.svelte.d.ts +2 -0
  93. package/dist/typo/P.svelte +3 -1
  94. package/dist/typo/P.svelte.d.ts +2 -0
  95. package/dist/utils/StringOrComponentOrSnippet.svelte +13 -0
  96. package/dist/utils/StringOrComponentOrSnippet.svelte.d.ts +17 -0
  97. package/dist/utils/index.d.ts +8 -0
  98. package/dist/utils/index.js +5 -0
  99. package/dist/utils/keyboard.svelte.d.ts +3 -0
  100. package/dist/utils/keyboard.svelte.js +142 -0
  101. package/dist/utils/transitions.js +14 -7
  102. package/package.json +9 -13
  103. package/dist/datatable/DataTable.svelte +0 -31
  104. package/dist/datatable/DataTable.svelte.d.ts +0 -20
  105. package/dist/datatable/DataTableColumn.svelte +0 -20
  106. package/dist/datatable/DataTableColumn.svelte.d.ts +0 -18
  107. package/dist/datatable/DataTableRow.svelte +0 -59
  108. package/dist/datatable/DataTableRow.svelte.d.ts +0 -21
  109. package/dist/datatable/index.d.ts +0 -3
  110. package/dist/datatable/index.js +0 -3
  111. package/dist/form/server.d.ts +0 -21
  112. package/dist/form/server.js +0 -48
@@ -1,4 +1,4 @@
1
- <script>let {
1
+ <script lang="ts">let {
2
2
  children
3
3
  } = $props();
4
4
  </script>
@@ -1,4 +1,4 @@
1
- <script>const {
1
+ <script lang="ts">const {
2
2
  items,
3
3
  separator = "/",
4
4
  contained,
@@ -1,180 +1,196 @@
1
- <script>import { page } from "$app/stores";
1
+ <script lang="ts">import MenuItem from "./MenuItem.svelte";
2
+ import { isComponent } from "../utils/isSnippet.js";
3
+ import { createId } from "../utils/id.js";
4
+ import { slidefade } from "../utils/transitions.js";
5
+ import UiContent from "../layout/UIContent.svelte";
6
+ import { arrowNavigation, getNextFocusableElement, matchOnType } from "../utils/keyboard.svelte.js";
7
+ import StringOrComponentOrSnippet from "../utils/StringOrComponentOrSnippet.svelte";
2
8
  let {
3
- items
9
+ open = $bindable(false),
10
+ items,
11
+ trigger
4
12
  } = $props();
5
- function parseHref(href) {
6
- if (!href)
7
- return {
8
- href: void 0,
9
- exact: false
10
- };
11
- if (href.endsWith("*")) {
12
- return {
13
- href: href.slice(0, -1),
14
- exact: false
15
- };
13
+ let _open = $state(open);
14
+ let triggerEl = $state(null);
15
+ let contentEl = $state(null);
16
+ let menuEl = $state(null);
17
+ let menuHeight = $state(0);
18
+ let menuWidth = $state(0);
19
+ const id = createId();
20
+ const fudge = 16;
21
+ $effect(() => {
22
+ if (_open) {
23
+ window.addEventListener("click", clickoutside);
24
+ window.addEventListener("keydown", onkeydown);
25
+ } else {
26
+ window.removeEventListener("click", clickoutside);
27
+ window.removeEventListener("keydown", onkeydown);
16
28
  }
17
- return {
18
- href,
19
- exact: true
20
- };
29
+ });
30
+ function toggle() {
31
+ _open = !_open;
21
32
  }
22
- function parseLinks(items2) {
23
- return items2.map((item) => {
24
- if (item.href) {
25
- return {
26
- ...item,
27
- ...parseHref(item.href)
28
- };
29
- }
30
- if (!item.children)
31
- return item;
32
- return {
33
- ...item,
34
- children: parseLinks(item.children)
35
- };
36
- });
33
+ let origin = $derived.by(() => {
34
+ if (!triggerEl || !contentEl)
35
+ return "top-left";
36
+ const triggerPos = triggerEl.getBoundingClientRect();
37
+ const elPos = contentEl.getBoundingClientRect();
38
+ const isOffRight = triggerPos.left + elPos.width > window.innerWidth - fudge;
39
+ const isOffBottom = triggerPos.bottom + elPos.height > window.innerHeight - fudge;
40
+ let text = "top left";
41
+ if (isOffRight)
42
+ text = text.replace("left", "right");
43
+ if (isOffBottom)
44
+ text = text.replace("top", "bottom");
45
+ return text;
46
+ });
47
+ let posLeft = $derived.by(() => {
48
+ if (!triggerEl || !contentEl)
49
+ return 0;
50
+ const triggerPos = triggerEl.getBoundingClientRect();
51
+ const isOffRight = triggerPos.left + menuWidth > window.innerWidth - fudge;
52
+ if (isOffRight) {
53
+ return triggerPos.left + triggerPos.width - menuWidth;
54
+ }
55
+ return triggerPos.left;
56
+ });
57
+ let posTop = $derived.by(() => {
58
+ if (!triggerEl || !contentEl)
59
+ return 0;
60
+ const triggerPos = triggerEl.getBoundingClientRect();
61
+ const scrollY = window.scrollY;
62
+ const isOffBottom = triggerPos.bottom + menuHeight > window.innerHeight - fudge;
63
+ if (isOffBottom) {
64
+ return triggerPos.top - menuHeight - triggerPos.height + scrollY;
65
+ }
66
+ return triggerPos.top + scrollY;
67
+ });
68
+ function onclick(e) {
69
+ e.preventDefault();
70
+ _open = !_open;
71
+ }
72
+ function clickoutside(e) {
73
+ if (!_open)
74
+ return;
75
+ if (contentEl && !contentEl.contains(e.target) && !triggerEl?.contains(e.target)) {
76
+ _open = false;
77
+ }
78
+ }
79
+ function onkeydown(e) {
80
+ if (!_open)
81
+ return;
82
+ const active = document.activeElement;
83
+ switch (e.key) {
84
+ case "Escape":
85
+ e.preventDefault();
86
+ _open = false;
87
+ break;
88
+ case "Tab":
89
+ e.preventDefault();
90
+ e.stopPropagation();
91
+ _open = false;
92
+ setTimeout(() => {
93
+ const nextEl = getNextFocusableElement(menuEl, triggerEl, e.shiftKey ? "previous" : "next");
94
+ console.log("nextEl", nextEl);
95
+ if (nextEl) {
96
+ nextEl.focus();
97
+ if (nextEl.tagName === "BUTTON" || nextEl.tagName === "A" && nextEl.parentElement?.classList.contains("Trigger")) {
98
+ nextEl.click();
99
+ }
100
+ }
101
+ }, 0);
102
+ break;
103
+ case "ArrowDown":
104
+ e.preventDefault();
105
+ arrowNavigation(contentEl, "down");
106
+ matchOnType(contentEl, e);
107
+ break;
108
+ case "ArrowUp":
109
+ e.preventDefault();
110
+ arrowNavigation(contentEl, "up");
111
+ matchOnType(contentEl, e);
112
+ break;
113
+ case "Enter":
114
+ case "Space":
115
+ e.preventDefault();
116
+ active.click();
117
+ break;
118
+ default:
119
+ matchOnType(contentEl, e);
120
+ }
37
121
  }
38
- const parsedItems = parseLinks(items);
39
122
  </script>
40
123
 
41
- <nav>
42
- <ul>
43
- {#snippet link(i)}
44
- <li aria-current={i.exact ? ($page?.url?.pathname === i.href ? 'page' : undefined) : ($page?.url?.pathname?.startsWith(i.href) ? 'page' : undefined)}>
45
- {#if i.href}
46
- <a href={i.href}>
47
- {#if i.icon}
48
- <svelte:component this={i.icon} />
49
- {/if}
50
- {i.label}
51
- </a>
52
- {:else}
53
- <span>
54
- {#if i.icon}
55
- <svelte:component this={i.icon} />
56
- {/if}
57
- {i.label}
58
- </span>
59
- {/if}
60
- {#if i.children}
61
- <ul>
62
- {#each i.children as child}
63
- {@render link(child)}
64
- {/each}
65
- </ul>
66
- {/if}
67
- </li>
68
- {/snippet}
69
- {#each parsedItems as item, index}
70
- {@render link(item)}
71
- {/each}
72
- </ul>
73
- </nav>
124
+ <UiContent>
125
+ <div class="Menu" bind:this={menuEl}>
126
+ <div
127
+ class="Trigger"
128
+ bind:this={triggerEl}
129
+ >
130
+ {#if typeof trigger === "string" || isComponent(trigger)}
131
+ <button type="button" class="button" {onclick} aria-haspopup="true" aria-controls={id} aria-expanded="{_open}">
132
+ <StringOrComponentOrSnippet content={trigger} />
133
+ </button>
134
+ {:else}
135
+ {@render trigger({ toggle: toggle, isOpen: _open })}
136
+ {/if}
137
+ </div>
138
+ {#if _open}
139
+ <div {id}
140
+ class="MenuContent"
141
+ role="menu"
142
+ bind:clientWidth={menuWidth}
143
+ bind:clientHeight={menuHeight}
144
+ bind:this={contentEl}
145
+ style="--left: {posLeft}px; --top: {posTop}px;"
146
+ transition:slidefade={{ y: 5, origin: origin, duration: 100 }}
147
+ >
148
+ <ul>
149
+ {#each items as item}
150
+ <MenuItem item={item} />
151
+ {/each}
152
+ </ul>
153
+ </div>
154
+ {/if}
155
+ </div>
156
+ </UiContent>
74
157
 
75
158
  <style>
76
- nav {
77
- }
78
- ul {
79
- display: flex;
80
- list-style: none;
81
- padding: 0;
82
- margin: 0;
83
- }
84
- a, span {
85
- display: flex;
86
- align-items: center;
87
- padding: 0.5rem 0.75rem;
88
- text-decoration: none;
89
- font-weight: 500;
90
- color: var(--menu-link);
91
- }
92
- a:hover, span:hover {
93
- background: var(--menu-bg-hover);
94
- color: var(--menu-link-hover);
95
- }
96
- /** loop */
97
- ul > li > ul {
98
- display: none;
99
- position: absolute;
100
- flex-direction: column;
101
- top: 100%;
102
- left: 0;
103
- background: var(--menu-bg);
104
- border: var(--menu-border);
105
- }
106
- ul > li:hover > ul,
107
- ul > li:focus-within > ul {
108
- display: flex;
109
- }
110
- ul > li:hover,
111
- ul > li:focus-within {
112
- background: var(--menu-bg-hover);
113
- }
114
- ul > li:hover > a,
115
- ul > li:focus-within > a,
116
- ul > li:hover > span,
117
- ul > li:focus-within > span {
118
- color: var(--menu-link-hover);
119
- }
120
-
121
- ul > li {
122
- border-block-end: var(--menu-border);
159
+ .Menu {
123
160
  position: relative;
124
- white-space: nowrap;
125
161
  }
126
- ul > li:last-child {
127
- border-block-end: none;
128
- }
129
- ul > li > ul {
130
- left: 100%;
131
- top: -1px;
132
- }
133
- ul > li:has(ul) > a {
134
- padding-inline-end: 2rem;
135
- }
136
- ul > li:has(ul) > a::after {
137
- content: "▶";
138
- padding-inline-start: 0.5rem;
139
- font-size: 9px;
140
- position: absolute;
141
- right: 0.75rem;
142
- color: var(--menu-link);
143
- }
144
- /** top level */
145
- nav > ul {
146
- flex-direction: row;
147
- gap: 1px;
162
+
163
+ .Trigger {
148
164
  position: relative;
165
+ display: inline-flex;
149
166
  }
150
- nav > ul > li {
151
- border-block-end: none;
152
- }
153
- nav > ul > li > a {
154
- border-radius: var(--border-radius);
155
- }
156
- nav > ul > li > a:hover {
167
+
168
+ .MenuContent {
169
+ position: fixed;
170
+ left: var(--left, 0);
171
+ top: var(--top, 0);
172
+ margin: 0;
173
+ z-index: 1000;
174
+ margin: 0;
175
+ border: var(--menu-border);
157
176
  border-radius: var(--border-radius);
177
+ box-shadow: 0 0.5rem 1rem var(--shadow);
178
+ background-color: var(--menu-bg);
179
+ width: var(--width, 25ch);
180
+ overflow: clip;
158
181
  }
159
- nav > ul > li > ul {
160
- top: 100%;
161
- left: 0;
162
- background: var(--menu-bg);
163
- border: var(--menu-border);
164
- filter: drop-shadow(0 0.25rem 0.5rem var(--shadow));
182
+
183
+ .MenuContent:has(li:last-of-type[data-type="item"]) {
184
+ padding-block-end: 0.5rem;
165
185
  }
166
- nav > ul > li:has(ul) > a {
167
- padding: 0.75rem 1rem;
186
+
187
+ nav[aria-expanded="true"] {
188
+ display: block;
168
189
  }
169
- nav > ul > li:has(ul) > a::after {
170
- content: "";
190
+
191
+ ul {
192
+ margin: 0;
193
+ list-style: none;
171
194
  padding: 0;
172
195
  }
173
- ul > li[aria-current="page"] a {
174
- background: var(--menu-bg-active);
175
- color: var(--menu-link-active);
176
- }
177
- ul > li[aria-current="page"] a:hover {
178
- color: var(--menu-link-active-hover);
179
- }
180
- </style>
196
+ </style>
@@ -1,9 +1,17 @@
1
1
  import { SvelteComponent } from "svelte";
2
- import type { MenuItem } from "./MenuTypes.js";
2
+ import type { ComponentType, Snippet } from "svelte";
3
+ import type { MenuItem as Item } from "./MenuTypes.js";
3
4
  declare const __propDef: {
4
5
  props: {
5
- /** Menu items to display */
6
- items: MenuItem[];
6
+ /** Whether the menu is open */
7
+ open?: boolean | undefined;
8
+ /** The items to display in the menu */
9
+ items: Item[];
10
+ /** The trigger for the menu */
11
+ trigger: string | ComponentType | Snippet<[{
12
+ toggle: () => void;
13
+ isOpen: boolean;
14
+ }]>;
7
15
  };
8
16
  events: {
9
17
  [evt: string]: CustomEvent<any>;
@@ -0,0 +1,122 @@
1
+ <script lang="ts">import StringOrComponentOrSnippet from "../utils/StringOrComponentOrSnippet.svelte";
2
+ import { isStatusColor } from "../utils/color.js";
3
+ import { isComponent, isSnippet } from "../utils/isSnippet.js";
4
+ let {
5
+ item
6
+ } = $props();
7
+ let isSet = $derived(item.type !== "divider" ? isStatusColor(item.color) : false);
8
+ </script>
9
+
10
+ <li class:divider={item.type === 'divider'} class:header={item.type === 'header'} data-type="{item.type}" style="--color: {isSet && item.type !== 'divider' ? 'var(--status-'+item.color+')' : (item.type !== 'divider' && item.color ? item.color : 'var(--menu-text)')}">
11
+ {#if item.type === 'divider'}
12
+ <hr />
13
+ {:else if item.type === 'header'}
14
+ <div class="Header">
15
+ <StringOrComponentOrSnippet content={item.content} />
16
+ </div>
17
+ {:else if item.type === 'item'}
18
+ {#if item.href}
19
+ <a href="{item.href}" class="Item">
20
+ <span class="Content">
21
+ <StringOrComponentOrSnippet content={item.content} />
22
+ </span>
23
+ {#if item.shortcut}
24
+ <span class="Shortcut">{item.shortcut}</span>
25
+ {/if}
26
+ </a>
27
+ {:else if item.onclick}
28
+ <button type="button" onclick={(e) => item.type === 'item' ? item.onclick!(e, item) : undefined} class="Item">
29
+ <span class="Content">
30
+ <StringOrComponentOrSnippet content={item.content} />
31
+ </span>
32
+ {#if item.shortcut}
33
+ <span class="Shortcut">{item.shortcut}</span>
34
+ {/if}
35
+ </button>
36
+ {:else if isSnippet(item.content)}
37
+ <div class="Item Custom">
38
+ {@render item.content()}
39
+ </div>
40
+ {:else if isComponent(item.content)}
41
+ <div class="Item Custom">
42
+ <svelte:component this={item.content} />
43
+ </div>
44
+ {/if}
45
+ {/if}
46
+ </li>
47
+
48
+ <style>
49
+ li {
50
+ margin: 0;
51
+ list-style: none;
52
+ padding: 0;
53
+ user-select: none;
54
+ }
55
+
56
+ li .Item,
57
+ li .Header {
58
+ font-size: 1em;
59
+ text-align: left;
60
+ padding-block: 0.5rem;
61
+ padding-inline: 1rem;
62
+ display: inline-flex;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ width: 100%;
66
+ color: inherit;
67
+ text-decoration: none;
68
+ color: var(--color);
69
+ --inset-block: 0.5rem;
70
+ --inset-inline: 1rem;
71
+ }
72
+
73
+ li .Header {
74
+ font-weight: 600;
75
+ }
76
+
77
+ li .Item:not(.Custom):hover,
78
+ li .Item:not(.Custom):focus-visible {
79
+ background-color: var(--menu-bg-hover);
80
+ cursor: pointer;
81
+ outline: none;
82
+ }
83
+
84
+ li .Item span.Shortcut {
85
+ font-size: max(0.75em, 9px);
86
+ text-align: right;
87
+ color: var(--text-subtle);
88
+ }
89
+
90
+ li .Item:not(.Custom):active {
91
+ scale: 1;
92
+ }
93
+
94
+ li.divider {
95
+ padding-block: 0.5rem;
96
+ }
97
+
98
+ hr {
99
+ display: block;
100
+ border: none;
101
+ margin: 0;
102
+ border-top: 1px solid var(--border-color);
103
+ }
104
+
105
+ li:first-child[data-type="item"] {
106
+ margin-block-start: 0.5rem;
107
+ }
108
+
109
+ li:first-child[data-type="header"]:has(+ li[data-type="item"]) {
110
+ margin-block-end: 0.5rem;
111
+ }
112
+
113
+ li:nth-last-child(2)[data-type="item"]:has(+ li[data-type="header"]:last-child) {
114
+ margin-block-end: 0.5rem;
115
+ }
116
+
117
+ @media (pointer: none) {
118
+ li .Item span.Shortcut {
119
+ display: none;
120
+ }
121
+ }
122
+ </style>
@@ -0,0 +1,17 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import type { MenuItem as Item } from "./MenuTypes.js";
3
+ declare const __propDef: {
4
+ props: {
5
+ item: Item;
6
+ };
7
+ events: {
8
+ [evt: string]: CustomEvent<any>;
9
+ };
10
+ slots: {};
11
+ };
12
+ export type MenuItemProps = typeof __propDef.props;
13
+ export type MenuItemEvents = typeof __propDef.events;
14
+ export type MenuItemSlots = typeof __propDef.slots;
15
+ export default class MenuItem extends SvelteComponent<MenuItemProps, MenuItemEvents, MenuItemSlots> {
16
+ }
17
+ export {};
@@ -1,11 +1,32 @@
1
+ import type { StatusColorOrString } from "../utils/color.js";
1
2
  import type { ComponentType, Snippet } from "svelte";
2
3
  export type MenuItem = {
4
+ /** Type of menu item to render. */
5
+ type: 'divider';
6
+ } | {
7
+ /** Type of menu item to render. */
8
+ type: 'header';
3
9
  /** Text label of the item to display to the user. */
4
- label: string;
5
- /** Path or URL to use for the menu item. If the href ends with a star (*), it will match any path that starts with the given path. This allows for nested active menu items. */
6
- href?: string;
10
+ content: string | ComponentType | Snippet;
11
+ /** Color to use for the item. */
12
+ color?: StatusColorOrString;
13
+ } | {
14
+ /** Type of menu item to render. */
15
+ type: 'item';
16
+ /** Text label of the item to display to the user. */
17
+ content: string | ComponentType | Snippet;
18
+ /** Keyboard shortcut to display next to the item. */
19
+ shortcut?: string;
7
20
  /** Icon to display. Pass either a Svelte Component or an URL. Use the Icon component to recolor your icons according to the user theme. */
8
21
  icon?: string | ComponentType;
22
+ /** Path or URL to use for the menu item. */
23
+ href?: string;
24
+ /** Click event handler. */
25
+ onclick?: (event: MouseEvent, item: MenuItem) => void;
26
+ /** If true, disables the item. */
27
+ disabled?: boolean;
28
+ /** Color to use for the item. */
29
+ color?: StatusColorOrString;
9
30
  /** Menu item children. Pass an array of menu items to create a nested menu. */
10
31
  children?: MenuItem[];
11
32
  };