@torpor/ui 0.3.6 → 0.4.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.
Files changed (89) hide show
  1. package/dist/Accordion/Accordion.torp +26 -25
  2. package/dist/Accordion/AccordionItem.torp +3 -3
  3. package/dist/Accordion/AccordionTypes.ts +5 -5
  4. package/dist/Accordion/index.d.ts +2 -2
  5. package/dist/Calendar/CalendarTypes.ts +1 -1
  6. package/dist/Charts/BarChart.torp +159 -0
  7. package/dist/Charts/DataSeries.ts +5 -0
  8. package/dist/Charts/GridLines.torp +65 -0
  9. package/dist/Charts/LineChart.torp +196 -0
  10. package/dist/Charts/PieChart.torp +145 -0
  11. package/dist/Charts/ScatterChart.torp +215 -0
  12. package/dist/Charts/SparkLine.torp +71 -0
  13. package/dist/Charts/XAxis.torp +66 -0
  14. package/dist/Charts/YAxis.torp +47 -0
  15. package/dist/Charts/index.d.ts +220 -0
  16. package/dist/Charts/index.js +34 -0
  17. package/dist/Charts/index.js.map +1 -0
  18. package/dist/Contextual/Contextual.torp +8 -3
  19. package/dist/Contextual/ContextualTypes.ts +1 -1
  20. package/dist/Dialog/Dialog.torp +12 -16
  21. package/dist/Dialog/DialogButton.torp +3 -0
  22. package/dist/Dialog/DialogTypes.ts +2 -2
  23. package/dist/Dialog/index.d.ts +2 -0
  24. package/dist/Disclosure/Disclosure.torp +3 -3
  25. package/dist/Disclosure/DisclosureTypes.ts +1 -1
  26. package/dist/Drawer/Drawer.torp +2 -2
  27. package/dist/Drawer/DrawerTypes.ts +1 -1
  28. package/dist/Form/CheckBox.torp +1 -2
  29. package/dist/Form/Input.torp +1 -1
  30. package/dist/Form/MessageSummary.torp +38 -0
  31. package/dist/Form/TextArea.torp +3 -0
  32. package/dist/Form/index.d.ts +25 -1
  33. package/dist/Form/index.js +4 -0
  34. package/dist/ListBox/ListBox.torp +271 -0
  35. package/dist/ListBox/ListBoxItem.torp +107 -0
  36. package/dist/ListBox/ListBoxSeparator.torp +26 -0
  37. package/dist/ListBox/ListBoxTypes.ts +23 -0
  38. package/dist/ListBox/index.d.ts +97 -0
  39. package/dist/ListBox/index.js +14 -0
  40. package/dist/ListBox/index.js.map +1 -0
  41. package/dist/Menu/Menu.torp +19 -14
  42. package/dist/Menu/MenuTypes.ts +5 -4
  43. package/dist/MenuBar/MenuBarItem.torp +5 -8
  44. package/dist/MenuBar/MenuBarTypes.ts +2 -2
  45. package/dist/Modal/Modal.torp +7 -2
  46. package/dist/Modal/ModalTypes.ts +1 -1
  47. package/dist/NavMenu/NavMenu.torp +7 -0
  48. package/dist/NavMenu/NavMenuButton.torp +5 -2
  49. package/dist/NavMenu/NavMenuPopout.torp +1 -1
  50. package/dist/NavMenu/{NavMenuPopoutButton.torp → NavMenuPopoutTrigger.torp} +4 -4
  51. package/dist/NavMenu/NavMenuSeparator.torp +2 -1
  52. package/dist/NavMenu/NavMenuTypes.ts +4 -3
  53. package/dist/NavMenu/index.d.ts +22 -18
  54. package/dist/NavMenu/index.js +4 -4
  55. package/dist/Pagination/Pagination.torp +145 -0
  56. package/dist/Pagination/PaginationItem.torp +100 -0
  57. package/dist/Pagination/PaginationTypes.ts +25 -0
  58. package/dist/Pagination/buildPages.ts +57 -0
  59. package/dist/Pagination/index.d.ts +53 -0
  60. package/dist/Pagination/index.js +40 -0
  61. package/dist/Pagination/index.js.map +1 -0
  62. package/dist/Popover/Popover.torp +8 -3
  63. package/dist/Popover/PopoverTypes.ts +1 -1
  64. package/dist/SelectBox/SelectBox.torp +136 -0
  65. package/dist/SelectBox/SelectBoxContent.torp +81 -0
  66. package/dist/SelectBox/SelectBoxInput.torp +95 -0
  67. package/dist/SelectBox/SelectBoxTrigger.torp +41 -0
  68. package/dist/SelectBox/SelectBoxTypes.ts +18 -0
  69. package/dist/SelectBox/index.d.ts +127 -0
  70. package/dist/SelectBox/index.js +18 -0
  71. package/dist/SelectBox/index.js.map +1 -0
  72. package/dist/TabGroup/TabGroup.torp +3 -3
  73. package/dist/TabGroup/TabGroupTypes.ts +2 -2
  74. package/dist/ToolBar/ToolBar.torp +198 -0
  75. package/dist/ToolBar/ToolBarButton.torp +57 -0
  76. package/dist/ToolBar/ToolBarElement.torp +55 -0
  77. package/dist/ToolBar/ToolBarPopout.torp +97 -0
  78. package/dist/ToolBar/ToolBarPopoutContent.torp +92 -0
  79. package/dist/ToolBar/ToolBarPopoutTrigger.torp +138 -0
  80. package/dist/ToolBar/ToolBarSeparator.torp +25 -0
  81. package/dist/ToolBar/ToolBarTypes.ts +35 -0
  82. package/dist/ToolBar/index.d.ts +212 -0
  83. package/dist/ToolBar/index.js +30 -0
  84. package/dist/ToolBar/index.js.map +1 -0
  85. package/dist/metafile-esm.json +1 -1
  86. package/dist/utils/PopoutTypes.ts +35 -0
  87. package/dist/utils/chartColors.ts +17 -0
  88. package/dist/utils/chartUtils.ts +71 -0
  89. package/package.json +22 -2
@@ -0,0 +1,271 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import getId from "../utils/getId";
3
+ import { PopoutContextName, type PopoutContext, type HandleButtonPress } from "../utils/PopoutTypes";
4
+ import { ListBoxContextName, type ListBoxContext, type ItemState } from "./ListBoxTypes";
5
+
6
+ // TODO: orientation
7
+
8
+ interface ListBoxProps {
9
+ /** An ID for the root element */
10
+ id?: string;
11
+ /** Classes for the root element */
12
+ class?: ClassValue,
13
+ /** Styles for the root element */
14
+ style?: StyleValue,
15
+ /** Whether a single ListBoxItem or multiple ListBoxItems can be selected at the same time */
16
+ type?: "single" | "multiple",
17
+ /** The value of the selected ListBoxItem, or an array of values if the type is "multiple" */
18
+ value?: any | any[],
19
+ /** If set to true, the user cannot interact with any items in the ListBox */
20
+ disabled?: boolean,
21
+ /** An ARIA label for describing the ListBox to screen readers */
22
+ ariaLabel?: string | undefined,
23
+ /** Raised when the selected item(s) have changed */
24
+ onchange?: (value: any | any[]) => void,
25
+ }
26
+
27
+ /**
28
+ * A list of options that a user can select.
29
+ *
30
+ * See [the WAI ARIA guidelines for ListBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/).
31
+ *
32
+ * The structure of an ListBox is:
33
+ *
34
+ * ```
35
+ * <ListBox>
36
+ * <ListBoxItem />
37
+ * <ListBoxSeparator /> (optional)
38
+ * </ListBox>
39
+ * ```
40
+ */
41
+ export default function ListBox($props: ListBoxProps | undefined) {
42
+ let defaultId = getId();
43
+ let type = $props?.type ?? "single";
44
+
45
+ let $state = $watch({
46
+ value: $props?.value ?? (type === "single" ? undefined : [])
47
+ });
48
+
49
+ // Update $state on $props change
50
+ $run(() => {
51
+ $state.value = $props?.value ?? (type === "single" ? undefined : [])
52
+ });
53
+
54
+ // Update $props on $state change
55
+ $run(() => {
56
+ if ($props !== undefined) {
57
+ $props.value = $state.value;
58
+ }
59
+ });
60
+
61
+ let itemStates: ItemState[] = [];
62
+
63
+ // This is used to assign automatic indexes to items where needed
64
+ let nextIndex = 0;
65
+
66
+ // Maybe get stuff out of a popout context
67
+ let handleButton: HandleButtonPress | undefined = undefined;
68
+ const popoutContext = $context[PopoutContextName] as PopoutContext;
69
+ if (popoutContext) {
70
+ handleButton = popoutContext.handleButton;
71
+
72
+ //popoutContext.handleClickOutside = handleClickOutside;
73
+ // Set the focusFirstElement method in the PopoutContext so that it can be
74
+ // called after everything has been shown
75
+ popoutContext.focusFirstElement = focusFirstElement;
76
+ popoutContext.focusLastElement = focusLastElement;
77
+
78
+ // Set the content ID so that it can be used with aria-controls in AccordionTrigger
79
+ popoutContext.state.contentId = $props?.id ?? defaultId;
80
+ }
81
+
82
+ // Set the context to pass down to items, with functions for each item to call
83
+ let context: ListBoxContext = {
84
+ registerItem,
85
+ removeItem,
86
+ toggleItem,
87
+ handleKey,
88
+ };
89
+ $context[ListBoxContextName] = context;
90
+
91
+ function focusFirstElement() {
92
+ if (itemStates.length > 0) {
93
+ itemStates[0].setFocused();
94
+ }
95
+ }
96
+
97
+ function focusLastElement() {
98
+ if (itemStates.length > 0) {
99
+ itemStates.at(-1)!.setFocused();
100
+ }
101
+ }
102
+
103
+ $run(() => {
104
+ // Get the value to ensure that this effect will be subscribed
105
+ let value = $state.value;
106
+
107
+ // And set the expanded item(s)
108
+ switch (type) {
109
+ case "single": {
110
+ for (let item of itemStates) {
111
+ item.selected = item.value === value;
112
+ }
113
+ break;
114
+ }
115
+ case "multiple": {
116
+ if (!Array.isArray(value)) {
117
+ value = [value];
118
+ }
119
+ for (let item of itemStates) {
120
+ item.selected = value.indexOf(item.value) !== -1;
121
+ }
122
+ break;
123
+ }
124
+ }
125
+ })
126
+
127
+ $run(() => {
128
+ let disabled = $props?.disabled;
129
+ itemStates.forEach((s) => s.parentDisabled = disabled === true);
130
+ });
131
+
132
+ // Dispatch the change event when the value changes
133
+ let firstChange = true;
134
+ $run(() => {
135
+ const onchange = $props?.onchange;
136
+ const value = $state.value;
137
+ if (firstChange) {
138
+ firstChange = false;
139
+ } else if (onchange) {
140
+ onchange(value);
141
+ }
142
+ });
143
+
144
+ function registerItem(itemState: ItemState) {
145
+ // If an index wasn't set for the item, set it automatically
146
+ if (itemState.index === -1) {
147
+ itemState.index = nextIndex++;
148
+ }
149
+
150
+ // If a value wasn't set for the item, set it to the index
151
+ if (!itemState.value) {
152
+ itemState.value = itemState.index;
153
+ }
154
+
155
+ // If we have a value, set whether the item should be selected
156
+ if ($state.value !== undefined && $state.value !== null) {
157
+ switch (type) {
158
+ case "single": {
159
+ itemState.selected = $state.value === itemState.value;
160
+ break;
161
+ }
162
+ case "multiple": {
163
+ itemState.selected = $state.value.includes(itemState.value);
164
+ break;
165
+ }
166
+ }
167
+ }
168
+
169
+ // Set whether the ListBox itself is disabled
170
+ itemState.parentDisabled = $props?.disabled === true
171
+
172
+ // Add the item's state to the array
173
+ itemStates.splice(itemState.index, 0, itemState);
174
+ }
175
+
176
+ // TODO: I think this should be done by value
177
+ function removeItem(itemIndex: number) {
178
+ // Remove the item and re-index
179
+ let index = itemStates.findIndex((item) => item.index === itemIndex);
180
+ if (index !== -1) {
181
+ itemStates.splice(itemIndex, 1);
182
+ }
183
+ itemStates.forEach((item, i) => (item.index = i));
184
+ }
185
+
186
+ function toggleItem(value: string) {
187
+ switch (type) {
188
+ case "single": {
189
+ for (let item of itemStates) {
190
+ if (item.value === value) {
191
+ $state.value = item.selected ? "" : item.value;
192
+ break;
193
+ }
194
+ }
195
+ // Pass this along to the containing popout if applicable, so
196
+ // that the popout can be closed
197
+ if (handleButton) {
198
+ handleButton("confirm", value)
199
+ }
200
+ break;
201
+ }
202
+ case "multiple": {
203
+ let newValue = [];
204
+ for (let item of itemStates) {
205
+ if (
206
+ (item.value === value && !item.selected) ||
207
+ (item.value !== value && item.selected)
208
+ ) {
209
+ newValue.push(item.value);
210
+ }
211
+ }
212
+ $state.value = newValue.sort();
213
+ break;
214
+ }
215
+ }
216
+ }
217
+
218
+ function handleKey(index: number, e: KeyboardEvent) {
219
+ switch (e.key) {
220
+ case "Up":
221
+ case "ArrowUp": {
222
+ if (index > 0) {
223
+ e.preventDefault();
224
+ itemStates[index - 1].setFocused();
225
+ }
226
+ break;
227
+ }
228
+ case "Down":
229
+ case "ArrowDown": {
230
+ if (index < itemStates.length - 1) {
231
+ e.preventDefault();
232
+ itemStates[index + 1].setFocused();
233
+ }
234
+ break;
235
+ }
236
+ case "Home": {
237
+ if (index > 0) {
238
+ e.preventDefault();
239
+ itemStates[0].setFocused();
240
+ }
241
+ break;
242
+ }
243
+ case "End": {
244
+ if (index < itemStates.length - 1) {
245
+ e.preventDefault();
246
+ itemStates[itemStates.length - 1].setFocused();
247
+ }
248
+ break;
249
+ }
250
+ case "Escape": {
251
+ if (handleButton) {
252
+ handleButton("cancel")
253
+ }
254
+ break;
255
+ }
256
+ }
257
+ }
258
+
259
+ @render {
260
+ <div
261
+ id={$props?.id ?? defaultId}
262
+ class={["torp-list-box", $props?.class]}
263
+ {$props?.style}
264
+ role="listbox"
265
+ aria-label={$props?.ariaLabel}
266
+ aria-multiselectable={type === "multiple" ? "true" : undefined}
267
+ >
268
+ <slot />
269
+ </div>
270
+ }
271
+ }
@@ -0,0 +1,107 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import { ListBoxContextName, type ItemState, type ListBoxContext } from "./ListBoxTypes";
3
+
4
+ interface ListBoxItemProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Classes for the root element */
8
+ class?: ClassValue,
9
+ /** Styles for the root element */
10
+ style?: StyleValue,
11
+ /** The index of this item in the ListBox. Set this if you will be inserting, removing or sorting items. If you don't set this, it will be set automatically */
12
+ index?: number,
13
+ /** A value for the item. Set this if you need more control over which item(s) are selected. If you don't set this, the value will be set to the item's initial index */
14
+ value?: string,
15
+ /** If set to true, the user cannot interact with this ListBoxItem */
16
+ disabled?: boolean,
17
+ /** Raised when this item is opened or closed */
18
+ ontoggle?: (open: boolean) => void,
19
+ }
20
+
21
+ /**
22
+ * An item in an ListBox.
23
+ */
24
+ export default function ListBoxItem($props: ListBoxItemProps | undefined) {
25
+ let $state: ItemState = $watch({
26
+ index: -1,
27
+ value: "",
28
+ selected: false,
29
+ disabled: $props?.disabled ?? false,
30
+ parentDisabled: false,
31
+ setFocused
32
+ })
33
+
34
+ let button: HTMLButtonElement;
35
+
36
+ // Get stuff out of the ListBoxContext
37
+ const context = $context[ListBoxContextName] as ListBoxContext;
38
+ if (!context) {
39
+ throw new Error("ListBoxItem must be contained within a ListBox");
40
+ }
41
+
42
+ // Register this item with the parent ListBox, which will handle toggling selected for all items
43
+ context.registerItem($state, setFocused);
44
+
45
+ // Remove the item from the parent ListBox when this item is destroyed
46
+ $run(() => {
47
+ return () => {
48
+ context.removeItem($state.index);
49
+ }
50
+ });
51
+
52
+ // Dispatch the toggle event when the value of selected changes
53
+ let firstToggle = true;
54
+ $run(() => {
55
+ const ontoggle = $props?.ontoggle;
56
+ const selected = $state.selected;
57
+ if (firstToggle) {
58
+ firstToggle = false;
59
+ } else if (ontoggle) {
60
+ ontoggle(selected);
61
+ }
62
+ });
63
+
64
+ // This function is called by the parent ListBox to focus this item's button
65
+ function setFocused() {
66
+ button.focus();
67
+ }
68
+
69
+ function handleClick() {
70
+ // Pass the value to the toggleItem method in the parent ListBox which will handle toggling
71
+ // the value of expanded for all items (e.g. to unselect other items if necessary)
72
+ context.toggleItem($state.value);
73
+ }
74
+
75
+ function handleKey(e: KeyboardEvent) {
76
+ // For testing
77
+ switch (e.key) {
78
+ case "Enter":
79
+ e.preventDefault();
80
+ context.toggleItem($state.value);
81
+ break;
82
+ default:
83
+ // Pass the key press up to the parent ListBox which will handle
84
+ // setting the focused button
85
+ context.handleKey($state.index, e);
86
+ break;
87
+ }
88
+ }
89
+
90
+ @render {
91
+ <button
92
+ {$props?.id}
93
+ class={["torp-list-box-item", $props?.class]}
94
+ {$props?.style}
95
+ role="option"
96
+ aria-selected={$state.selected ? "true" : "false"}
97
+ aria-disabled={$state.disabled ? "true" : undefined}
98
+ data-state={$state.selected ? "active" : undefined}
99
+ data-disabled={$state.disabled ? "true" : undefined}
100
+ onclick={handleClick}
101
+ onkeydown={handleKey}
102
+ &ref={button}
103
+ >
104
+ <slot />
105
+ </button>
106
+ }
107
+ }
@@ -0,0 +1,26 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+
3
+ interface ListBoxSeparatorProps {
4
+ /** An ID for the root element */
5
+ id?: string;
6
+ /** Classes for the root element */
7
+ class?: ClassValue,
8
+ /** Styles for the root element */
9
+ style?: StyleValue,
10
+ }
11
+
12
+ /**
13
+ * An element in a list box that separates logical sets of items.
14
+ */
15
+ export default function ListBoxSeparator($props: ListBoxSeparatorProps | undefined) {
16
+ @render {
17
+ <div
18
+ {$props?.id}
19
+ class={["torp-list-box-separator", $props?.class]}
20
+ {$props?.style}
21
+ role="separator"
22
+ >
23
+ <slot />
24
+ </div>
25
+ }
26
+ }
@@ -0,0 +1,23 @@
1
+ export const ListBoxContextName: unique symbol = Symbol.for("torp.ListBox");
2
+ export const ListBoxItemContextName: unique symbol = Symbol.for("torp.ListBoxItem");
3
+
4
+ export interface ListBoxContext {
5
+ /** Called from an ListBoxItem when it is added */
6
+ registerItem: (state: ItemState, setFocused: () => void) => void;
7
+ /** Called from an ListBoxItem when it is removed */
8
+ removeItem: (index: number) => void;
9
+ /** Called from an ListBoxItem when it is toggled */
10
+ toggleItem: (value: string) => void;
11
+ /** Called from an ListBoxItem when it receives a keyboard event */
12
+ handleKey: (index: number, e: KeyboardEvent) => void;
13
+ }
14
+
15
+ export interface ItemState {
16
+ index: number;
17
+ value: any;
18
+ selected: boolean;
19
+ disabled: boolean;
20
+ parentDisabled: boolean;
21
+ /** Called in the ListBox when an item needs to be focused */
22
+ setFocused: () => void;
23
+ }
@@ -0,0 +1,97 @@
1
+ import { type SlotRender } from "@torpor/view";
2
+
3
+
4
+ interface ListBoxProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Classes for the root element */
8
+ class?: ClassValue,
9
+ /** Styles for the root element */
10
+ style?: StyleValue,
11
+ /** Whether a single ListBoxItem or multiple ListBoxItems can be selected at the same time */
12
+ type?: "single" | "multiple",
13
+ /** The value of the selected ListBoxItem, or an array of values if the type is "multiple" */
14
+ value?: any | any[],
15
+ /** If set to true, the user cannot interact with any items in the ListBox */
16
+ disabled?: boolean,
17
+ /** An ARIA label for describing the ListBox to screen readers */
18
+ ariaLabel?: string | undefined,
19
+ /** Raised when the selected item(s) have changed */
20
+ onchange?: (value: any | any[]) => void,
21
+ }
22
+
23
+ /**
24
+ * A list of options that a user can select.
25
+ *
26
+ * See [the WAI ARIA guidelines for ListBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/).
27
+ *
28
+ * The structure of an ListBox is:
29
+ *
30
+ * ```
31
+ * <ListBox>
32
+ * <ListBoxItem />
33
+ * <ListBoxSeparator /> (optional)
34
+ * </ListBox>
35
+ * ```
36
+ */
37
+ declare function ListBox(
38
+ $parent: ParentNode,
39
+ $anchor: Node | null,
40
+ $props: ListBoxProps | undefined,
41
+ $context?: Record<PropertyKey, any>,
42
+ $slots?: Record<string, SlotRender>,
43
+ ): void;
44
+
45
+
46
+
47
+ interface ListBoxItemProps {
48
+ /** An ID for the root element */
49
+ id?: string;
50
+ /** Classes for the root element */
51
+ class?: ClassValue,
52
+ /** Styles for the root element */
53
+ style?: StyleValue,
54
+ /** The index of this item in the ListBox. Set this if you will be inserting, removing or sorting items. If you don't set this, it will be set automatically */
55
+ index?: number,
56
+ /** A value for the item. Set this if you need more control over which item(s) are selected. If you don't set this, the value will be set to the item's initial index */
57
+ value?: string,
58
+ /** If set to true, the user cannot interact with this ListBoxItem */
59
+ disabled?: boolean,
60
+ /** Raised when this item is opened or closed */
61
+ ontoggle?: (open: boolean) => void,
62
+ }
63
+
64
+ /**
65
+ * An item in an ListBox.
66
+ */
67
+ declare function ListBoxItem(
68
+ $parent: ParentNode,
69
+ $anchor: Node | null,
70
+ $props: ListBoxItemProps | undefined,
71
+ $context?: Record<PropertyKey, any>,
72
+ $slots?: Record<string, SlotRender>,
73
+ ): void;
74
+
75
+
76
+
77
+ interface ListBoxSeparatorProps {
78
+ /** An ID for the root element */
79
+ id?: string;
80
+ /** Classes for the root element */
81
+ class?: ClassValue,
82
+ /** Styles for the root element */
83
+ style?: StyleValue,
84
+ }
85
+
86
+ /**
87
+ * An element in a list box that separates logical sets of items.
88
+ */
89
+ declare function ListBoxSeparator(
90
+ $parent: ParentNode,
91
+ $anchor: Node | null,
92
+ $props: ListBoxSeparatorProps | undefined,
93
+ $context?: Record<PropertyKey, any>,
94
+ $slots?: Record<string, SlotRender>,
95
+ ): void;
96
+
97
+ export { ListBox, ListBoxItem, ListBoxSeparator };
@@ -0,0 +1,14 @@
1
+ // src/ListBox/ListBox.torp
2
+ import ListBox_default from "./ListBox.torp";
3
+
4
+ // src/ListBox/ListBoxItem.torp
5
+ import ListBoxItem_default from "./ListBoxItem.torp";
6
+
7
+ // src/ListBox/ListBoxSeparator.torp
8
+ import ListBoxSeparator_default from "./ListBoxSeparator.torp";
9
+ export {
10
+ ListBox_default as ListBox,
11
+ ListBoxItem_default as ListBoxItem,
12
+ ListBoxSeparator_default as ListBoxSeparator
13
+ };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,7 +1,5 @@
1
1
  import type { ClassValue, StyleValue } from "@torpor/view";
2
- import { ContextualContextName } from "../Contextual/ContextualTypes";
3
- import { ModalContextName } from "../Modal/ModalTypes";
4
- import { PopoverContextName, type PopoverContext } from "../Popover/PopoverTypes";
2
+ import { PopoutContextName, type PopoutContext } from "../utils/PopoutTypes";
5
3
  import {
6
4
  MenuContextName,
7
5
  type MenuContext,
@@ -46,21 +44,22 @@ export default function Menu($props: MenuProps | undefined) {
46
44
 
47
45
  // Get stuff out of the PopoverContext
48
46
  // HACK: share state in PopupState and extend in context/modal/popover
49
- const popoverContext = $context[ContextualContextName] ?? $context[ModalContextName] ?? $context[PopoverContextName] as PopoverContext;
50
- if (!popoverContext) {
51
- throw new Error("Menu must be contained within a Context, Modal or Popover");
47
+ const popoutContext = $context[PopoutContextName] as PopoutContext;
48
+ if (!popoutContext) {
49
+ throw new Error("Menu must be contained within a popout component");
52
50
  }
53
- const { setVisible, handleButton, visible } = popoverContext;
51
+ const { setVisible, handleButton, state } = popoutContext;
54
52
 
55
53
  // Check whether this is a menu in a popout
56
- const popoutContext = $context[MenuPopoutContextName] as MenuPopoutContext;
57
- const inPopout = !!popoutContext;
58
- const setPopoutVisible = popoutContext?.setVisible;
54
+ const menuPopoutContext = $context[MenuPopoutContextName] as MenuPopoutContext;
55
+ const inPopout = !!menuPopoutContext;
56
+ const setPopoutVisible = menuPopoutContext?.setVisible;
59
57
 
60
58
  // Set the focusFirstElement method in the PopoverContext(s) so that it can be called after everything has been shown
61
- popoverContext.focusFirstElement = focusFirstElement;
62
- if (popoutContext) {
63
- popoutContext.focusFirstElement = focusFirstElement;
59
+ popoutContext.focusFirstElement = focusFirstElement;
60
+ if (menuPopoutContext) {
61
+ menuPopoutContext.focusFirstElement = focusFirstElement;
62
+ menuPopoutContext.focusLastElement = focusLastElement;
64
63
  }
65
64
 
66
65
  // Set the context to pass down to items
@@ -69,7 +68,7 @@ export default function Menu($props: MenuProps | undefined) {
69
68
  handleButton,
70
69
  handleItemFocus,
71
70
  handleItemKey,
72
- visible,
71
+ state,
73
72
  registerItem
74
73
  };
75
74
  $context[MenuContextName] = context;
@@ -80,6 +79,12 @@ export default function Menu($props: MenuProps | undefined) {
80
79
  }
81
80
  }
82
81
 
82
+ function focusLastElement() {
83
+ if (itemStates.length > 0) {
84
+ itemStates.at(-1)!.setFocused();
85
+ }
86
+ }
87
+
83
88
  function registerItem(setFocused: () => void) {
84
89
  // Add the item's state to the array and return its index
85
90
  const newItemState: ItemState = {
@@ -1,7 +1,7 @@
1
- export const MenuContextName = "Menu";
2
- export const MenuButtonContextName = "MenuButton";
3
- export const MenuRadioGroupContextName = "MenuRadioGroup";
4
- export const MenuPopoutContextName = "MenuPopout";
1
+ export const MenuContextName: unique symbol = Symbol.for("torp.Menu");
2
+ export const MenuButtonContextName: unique symbol = Symbol.for("torp.MenuButton");
3
+ export const MenuRadioGroupContextName: unique symbol = Symbol.for("torp.MenuRadioGroup");
4
+ export const MenuPopoutContextName: unique symbol = Symbol.for("torp.MenuPopout");
5
5
 
6
6
  export interface MenuContext {
7
7
  setVisible: (value: boolean, result?: any) => void;
@@ -47,6 +47,7 @@ export interface MenuPopoutContext {
47
47
  };
48
48
  anchorElement?: HTMLElement;
49
49
  focusFirstElement?: () => void;
50
+ focusLastElement?: () => void;
50
51
  }
51
52
 
52
53
  export interface ItemState {
@@ -5,7 +5,7 @@ import {
5
5
  type MenuBarContext,
6
6
  type MenuBarItemContext
7
7
  } from "./MenuBarTypes";
8
- import { PopoverContextName, type PopoverContext } from "../Popover/PopoverTypes";
8
+ import { PopoutContextName, type PopoutContext } from "../utils/PopoutTypes";
9
9
 
10
10
  interface MenuBarItemProps {
11
11
  /** An ID for the root element */
@@ -59,17 +59,14 @@ export default function MenuBarItem($props: MenuBarItemProps | undefined) {
59
59
  $context[MenuBarItemContextName] = context;
60
60
 
61
61
  // Set the context to pass down to items
62
- let popoverContext: PopoverContext = {
63
- setVisible,
62
+ let popoutContext: PopoutContext = {
64
63
  handleButton,
65
- modal: false,
66
64
  state: $state,
67
- //anchorElement: anchor,
68
65
  };
69
- $context[PopoverContextName] = popoverContext;
66
+ $context[PopoutContextName] = popoutContext;
70
67
 
71
68
  $mount(() => {
72
- setVisible();
69
+ setVisible(false);
73
70
  });
74
71
 
75
72
  function setVisible(value: boolean) {
@@ -99,7 +96,7 @@ export default function MenuBarItem($props: MenuBarItemProps | undefined) {
99
96
  }
100
97
  });
101
98
 
102
- function handleButton(type: "confirm" | "cancel" | undefined, value?: any) {
99
+ function handleButton(_type: "confirm" | "cancel" | undefined, _value?: any) {
103
100
  menubarContext.state.active = false;
104
101
  setVisible(false);
105
102
  }
@@ -1,5 +1,5 @@
1
- export const MenuBarContextName = "MenuBar";
2
- export const MenuBarItemContextName = "MenuBarItem";
1
+ export const MenuBarContextName: unique symbol = Symbol.for("torp.MenuBar");
2
+ export const MenuBarItemContextName: unique symbol = Symbol.for("torp.MenuBarItem");
3
3
 
4
4
  export interface MenuBarContext {
5
5
  /** Called from a MenuBarItem when it is shown, to hide others */