@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.
- package/dist/Accordion/Accordion.torp +26 -25
- package/dist/Accordion/AccordionItem.torp +3 -3
- package/dist/Accordion/AccordionTypes.ts +5 -5
- package/dist/Accordion/index.d.ts +2 -2
- package/dist/Calendar/CalendarTypes.ts +1 -1
- package/dist/Charts/BarChart.torp +159 -0
- package/dist/Charts/DataSeries.ts +5 -0
- package/dist/Charts/GridLines.torp +65 -0
- package/dist/Charts/LineChart.torp +196 -0
- package/dist/Charts/PieChart.torp +145 -0
- package/dist/Charts/ScatterChart.torp +215 -0
- package/dist/Charts/SparkLine.torp +71 -0
- package/dist/Charts/XAxis.torp +66 -0
- package/dist/Charts/YAxis.torp +47 -0
- package/dist/Charts/index.d.ts +220 -0
- package/dist/Charts/index.js +34 -0
- package/dist/Charts/index.js.map +1 -0
- package/dist/Contextual/Contextual.torp +8 -3
- package/dist/Contextual/ContextualTypes.ts +1 -1
- package/dist/Dialog/Dialog.torp +12 -16
- package/dist/Dialog/DialogButton.torp +3 -0
- package/dist/Dialog/DialogTypes.ts +2 -2
- package/dist/Dialog/index.d.ts +2 -0
- package/dist/Disclosure/Disclosure.torp +3 -3
- package/dist/Disclosure/DisclosureTypes.ts +1 -1
- package/dist/Drawer/Drawer.torp +2 -2
- package/dist/Drawer/DrawerTypes.ts +1 -1
- package/dist/Form/CheckBox.torp +1 -2
- package/dist/Form/Input.torp +1 -1
- package/dist/Form/MessageSummary.torp +38 -0
- package/dist/Form/TextArea.torp +3 -0
- package/dist/Form/index.d.ts +25 -1
- package/dist/Form/index.js +4 -0
- package/dist/ListBox/ListBox.torp +271 -0
- package/dist/ListBox/ListBoxItem.torp +107 -0
- package/dist/ListBox/ListBoxSeparator.torp +26 -0
- package/dist/ListBox/ListBoxTypes.ts +23 -0
- package/dist/ListBox/index.d.ts +97 -0
- package/dist/ListBox/index.js +14 -0
- package/dist/ListBox/index.js.map +1 -0
- package/dist/Menu/Menu.torp +19 -14
- package/dist/Menu/MenuTypes.ts +5 -4
- package/dist/MenuBar/MenuBarItem.torp +5 -8
- package/dist/MenuBar/MenuBarTypes.ts +2 -2
- package/dist/Modal/Modal.torp +7 -2
- package/dist/Modal/ModalTypes.ts +1 -1
- package/dist/NavMenu/NavMenu.torp +7 -0
- package/dist/NavMenu/NavMenuButton.torp +5 -2
- package/dist/NavMenu/NavMenuPopout.torp +1 -1
- package/dist/NavMenu/{NavMenuPopoutButton.torp → NavMenuPopoutTrigger.torp} +4 -4
- package/dist/NavMenu/NavMenuSeparator.torp +2 -1
- package/dist/NavMenu/NavMenuTypes.ts +4 -3
- package/dist/NavMenu/index.d.ts +22 -18
- package/dist/NavMenu/index.js +4 -4
- package/dist/Pagination/Pagination.torp +145 -0
- package/dist/Pagination/PaginationItem.torp +100 -0
- package/dist/Pagination/PaginationTypes.ts +25 -0
- package/dist/Pagination/buildPages.ts +57 -0
- package/dist/Pagination/index.d.ts +53 -0
- package/dist/Pagination/index.js +40 -0
- package/dist/Pagination/index.js.map +1 -0
- package/dist/Popover/Popover.torp +8 -3
- package/dist/Popover/PopoverTypes.ts +1 -1
- package/dist/SelectBox/SelectBox.torp +136 -0
- package/dist/SelectBox/SelectBoxContent.torp +81 -0
- package/dist/SelectBox/SelectBoxInput.torp +95 -0
- package/dist/SelectBox/SelectBoxTrigger.torp +41 -0
- package/dist/SelectBox/SelectBoxTypes.ts +18 -0
- package/dist/SelectBox/index.d.ts +127 -0
- package/dist/SelectBox/index.js +18 -0
- package/dist/SelectBox/index.js.map +1 -0
- package/dist/TabGroup/TabGroup.torp +3 -3
- package/dist/TabGroup/TabGroupTypes.ts +2 -2
- package/dist/ToolBar/ToolBar.torp +198 -0
- package/dist/ToolBar/ToolBarButton.torp +57 -0
- package/dist/ToolBar/ToolBarElement.torp +55 -0
- package/dist/ToolBar/ToolBarPopout.torp +97 -0
- package/dist/ToolBar/ToolBarPopoutContent.torp +92 -0
- package/dist/ToolBar/ToolBarPopoutTrigger.torp +138 -0
- package/dist/ToolBar/ToolBarSeparator.torp +25 -0
- package/dist/ToolBar/ToolBarTypes.ts +35 -0
- package/dist/ToolBar/index.d.ts +212 -0
- package/dist/ToolBar/index.js +30 -0
- package/dist/ToolBar/index.js.map +1 -0
- package/dist/metafile-esm.json +1 -1
- package/dist/utils/PopoutTypes.ts +35 -0
- package/dist/utils/chartColors.ts +17 -0
- package/dist/utils/chartUtils.ts +71 -0
- package/package.json +22 -2
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/Pagination/Pagination.torp
|
|
2
|
+
import Pagination_default from "./Pagination.torp";
|
|
3
|
+
|
|
4
|
+
// src/Pagination/PaginationItem.torp
|
|
5
|
+
import PaginationItem_default from "./PaginationItem.torp";
|
|
6
|
+
|
|
7
|
+
// src/Pagination/buildPages.ts
|
|
8
|
+
function buildPages(count, number, pageSize = 1, maxPages = 9) {
|
|
9
|
+
const pageCount = Math.ceil(count / pageSize);
|
|
10
|
+
if (pageCount <= maxPages) {
|
|
11
|
+
return Array.from({ length: pageCount }).fill(0).map((_, i) => i + 1);
|
|
12
|
+
} else {
|
|
13
|
+
let start = number - Math.floor((maxPages - 1) / 2);
|
|
14
|
+
let end = number + Math.ceil((maxPages - 1) / 2);
|
|
15
|
+
if (start < 1) {
|
|
16
|
+
end += Math.abs(start) + 1;
|
|
17
|
+
start = 1;
|
|
18
|
+
} else if (end > pageCount) {
|
|
19
|
+
start -= end - pageCount;
|
|
20
|
+
end = pageCount;
|
|
21
|
+
}
|
|
22
|
+
const numbers = Array.from({ length: end - start + 1 }).fill(0).map((_, i) => start + i);
|
|
23
|
+
if (numbers[0] !== 1) {
|
|
24
|
+
numbers[0] = 1;
|
|
25
|
+
numbers[1] = "startgap";
|
|
26
|
+
}
|
|
27
|
+
const l = numbers.length;
|
|
28
|
+
if (numbers[l - 1] !== pageCount) {
|
|
29
|
+
numbers[l - 1] = pageCount;
|
|
30
|
+
numbers[l - 2] = "endgap";
|
|
31
|
+
}
|
|
32
|
+
return numbers;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
Pagination_default as Pagination,
|
|
37
|
+
PaginationItem_default as PaginationItem,
|
|
38
|
+
buildPages
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/Pagination/buildPages.ts"],"sourcesContent":["import { type PageNumber } from \"./PaginationTypes\";\n\n/**\n * Builds the pages that should be displayed for pagination.\n *\n * @param count The total number of pages (or items if the page size is greater than 1)\n * @param number The active page number\n * @param pageSize The number of items on each page\n * @param maxPages The maximum number of pages to display (gaps will be indicated with ellipses)\n */\nexport default function buildPages(\n\tcount: number,\n\tnumber: number,\n\tpageSize: number = 1,\n\tmaxPages: number = 9,\n): PageNumber[] {\n\t// Calculate the page count\n\tconst pageCount = Math.ceil(count / pageSize);\n\n\tif (pageCount <= maxPages) {\n\t\t// There\"s no need for ellipses, just return the numbers\n\t\treturn Array.from({ length: pageCount })\n\t\t\t.fill(0)\n\t\t\t.map((_, i) => i + 1);\n\t} else {\n\t\t// Get the start and end around the current page number\n\t\t// Use floor and ceil in case there is an even number of pages (e.g. if\n\t\t// maxPages is 8, there will be 3 numbers at the start and 4 at the end)\n\t\tlet start = number - Math.floor((maxPages - 1) / 2);\n\t\tlet end = number + Math.ceil((maxPages - 1) / 2);\n\t\tif (start < 1) {\n\t\t\tend += Math.abs(start) + 1;\n\t\t\tstart = 1;\n\t\t} else if (end > pageCount) {\n\t\t\tstart -= end - pageCount;\n\t\t\tend = pageCount;\n\t\t}\n\n\t\t// Build the numbers\n\t\tconst numbers: PageNumber[] = Array.from({ length: end - start + 1 })\n\t\t\t.fill(0)\n\t\t\t.map((_, i) => start + i);\n\n\t\t// Replace numbers at the start and end with ellipses if necessary\n\t\tif (numbers[0] !== 1) {\n\t\t\tnumbers[0] = 1;\n\t\t\tnumbers[1] = \"startgap\";\n\t\t}\n\t\tconst l = numbers.length;\n\t\tif (numbers[l - 1] !== pageCount) {\n\t\t\tnumbers[l - 1] = pageCount;\n\t\t\tnumbers[l - 2] = \"endgap\";\n\t\t}\n\n\t\treturn numbers;\n\t}\n}\n"],"mappings":";;;;;;;AAUe,SAAR,WACN,OACA,QACA,WAAmB,GACnB,WAAmB,GACJ;AAEf,QAAM,YAAY,KAAK,KAAK,QAAQ,QAAQ;AAE5C,MAAI,aAAa,UAAU;AAE1B,WAAO,MAAM,KAAK,EAAE,QAAQ,UAAU,CAAC,EACrC,KAAK,CAAC,EACN,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,EACtB,OAAO;AAIN,QAAI,QAAQ,SAAS,KAAK,OAAO,WAAW,KAAK,CAAC;AAClD,QAAI,MAAM,SAAS,KAAK,MAAM,WAAW,KAAK,CAAC;AAC/C,QAAI,QAAQ,GAAG;AACd,aAAO,KAAK,IAAI,KAAK,IAAI;AACzB,cAAQ;AAAA,IACT,WAAW,MAAM,WAAW;AAC3B,eAAS,MAAM;AACf,YAAM;AAAA,IACP;AAGA,UAAM,UAAwB,MAAM,KAAK,EAAE,QAAQ,MAAM,QAAQ,EAAE,CAAC,EAClE,KAAK,CAAC,EACN,IAAI,CAAC,GAAG,MAAM,QAAQ,CAAC;AAGzB,QAAI,QAAQ,CAAC,MAAM,GAAG;AACrB,cAAQ,CAAC,IAAI;AACb,cAAQ,CAAC,IAAI;AAAA,IACd;AACA,UAAM,IAAI,QAAQ;AAClB,QAAI,QAAQ,IAAI,CAAC,MAAM,WAAW;AACjC,cAAQ,IAAI,CAAC,IAAI;AACjB,cAAQ,IAAI,CAAC,IAAI;AAAA,IAClB;AAEA,WAAO;AAAA,EACR;AACD;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ClassValue, StyleValue } from "@torpor/view";
|
|
2
2
|
import { PopoverContextName, type Point, type PopoverContext, type PopoverState } from "./PopoverTypes";
|
|
3
|
+
import { PopoutContextName, type PopoutContext } from "../utils/PopoutTypes";
|
|
3
4
|
|
|
4
5
|
interface PopoverProps {
|
|
5
6
|
/** An ID for the root element */
|
|
@@ -62,11 +63,15 @@ export default function Popover($props: PopoverProps | undefined) {
|
|
|
62
63
|
handleButton,
|
|
63
64
|
handleClickOutside,
|
|
64
65
|
state: $state,
|
|
65
|
-
modal: $props?.modal,
|
|
66
|
+
//modal: $props?.modal,
|
|
66
67
|
anchorElement: $props?.anchor ? $unwrap($props.anchor) : undefined,
|
|
67
68
|
};
|
|
68
69
|
$context[PopoverContextName] = context;
|
|
69
70
|
|
|
71
|
+
// Set the context to pass down to items
|
|
72
|
+
let popoutContext: PopoutContext = context;
|
|
73
|
+
$context[PopoutContextName] = popoutContext;
|
|
74
|
+
|
|
70
75
|
// Dispatch the toggle event when the popover is opened or closed
|
|
71
76
|
let firstToggle = true;
|
|
72
77
|
$run(() => {
|
|
@@ -90,11 +95,11 @@ export default function Popover($props: PopoverProps | undefined) {
|
|
|
90
95
|
// Get the button's result
|
|
91
96
|
switch (type) {
|
|
92
97
|
case "confirm": {
|
|
93
|
-
result = value
|
|
98
|
+
result = value ?? true;
|
|
94
99
|
break;
|
|
95
100
|
}
|
|
96
101
|
case "cancel": {
|
|
97
|
-
result = value
|
|
102
|
+
result = value ?? false;
|
|
98
103
|
break;
|
|
99
104
|
}
|
|
100
105
|
default: {
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import type { ClassValue, StyleValue } from "@torpor/view";
|
|
2
|
+
import { SelectBoxContextName, type SelectBoxContext, type SelectBoxState } from "./SelectBoxTypes";
|
|
3
|
+
import { PopoutContextName, type PopoutContext } from "../utils/PopoutTypes";
|
|
4
|
+
|
|
5
|
+
interface SelectBoxProps {
|
|
6
|
+
/** An ID for the root element */
|
|
7
|
+
id?: string;
|
|
8
|
+
/** Classes for the root element */
|
|
9
|
+
class?: ClassValue,
|
|
10
|
+
/** Styles for the root element */
|
|
11
|
+
style?: StyleValue,
|
|
12
|
+
/** The data value selected by the user */
|
|
13
|
+
value?: any,
|
|
14
|
+
/** Whether the popout is visible */
|
|
15
|
+
visible?: boolean,
|
|
16
|
+
/** A function to be called when the user selects a response */
|
|
17
|
+
callback?: ((value: any) => void),
|
|
18
|
+
/** Raised when the popout is opened or closed */
|
|
19
|
+
ontoggle?: (open: boolean) => void,
|
|
20
|
+
/** Raised when the popout has opened */
|
|
21
|
+
onopen?: () => void,
|
|
22
|
+
/** Raised when the popout has closed */
|
|
23
|
+
onclose?: (result: any) => void,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* An input box for selecting a value from a popout ListBox or Dialog.
|
|
28
|
+
*
|
|
29
|
+
* See [the WAI ARIA guidelines for ComboBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
|
|
30
|
+
*
|
|
31
|
+
* The structure of a SelectBox is:
|
|
32
|
+
*
|
|
33
|
+
* ```
|
|
34
|
+
* <SelectBox>
|
|
35
|
+
* <SelectBoxInput />
|
|
36
|
+
* <SelectBoxTrigger /> (optional)
|
|
37
|
+
* <SelectBoxContent />
|
|
38
|
+
* </SelectBox>
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export default function SelectBox($props: SelectBoxProps | undefined) {
|
|
42
|
+
let $state: SelectBoxState = $watch({
|
|
43
|
+
visible: false,
|
|
44
|
+
value: $props?.value,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Sync props and state
|
|
48
|
+
$run(() => {
|
|
49
|
+
$state.visible = $props?.visible ?? false;
|
|
50
|
+
});
|
|
51
|
+
$run(() => {
|
|
52
|
+
if ($props !== undefined) {
|
|
53
|
+
$props.visible = $state.visible;
|
|
54
|
+
$props.value = $state.value;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
let result: any;
|
|
59
|
+
|
|
60
|
+
// Set the context to pass down to items
|
|
61
|
+
let context: SelectBoxContext = {
|
|
62
|
+
handleButton,
|
|
63
|
+
handleClickOutside,
|
|
64
|
+
state: $state,
|
|
65
|
+
};
|
|
66
|
+
$context[SelectBoxContextName] = context;
|
|
67
|
+
|
|
68
|
+
// Set the context to pass down to items
|
|
69
|
+
let popoutContext: PopoutContext = context;
|
|
70
|
+
$context[PopoutContextName] = popoutContext;
|
|
71
|
+
|
|
72
|
+
// Dispatch the toggle event when the popout is opened or closed
|
|
73
|
+
let firstToggle = true;
|
|
74
|
+
$run(() => {
|
|
75
|
+
const ontoggle = $props?.ontoggle;
|
|
76
|
+
const onopen = $props?.onopen;
|
|
77
|
+
const onclose = $props?.onclose;
|
|
78
|
+
const visible = $state.visible;
|
|
79
|
+
if (firstToggle) {
|
|
80
|
+
firstToggle = false;
|
|
81
|
+
} else {
|
|
82
|
+
if (ontoggle) ontoggle(visible);
|
|
83
|
+
if (visible) {
|
|
84
|
+
if (onopen) onopen()
|
|
85
|
+
} else {
|
|
86
|
+
if (onclose) onclose(result);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
function handleButton(type: "confirm" | "cancel" | undefined, value?: any) {
|
|
92
|
+
// Get the button's result
|
|
93
|
+
switch (type) {
|
|
94
|
+
case "confirm": {
|
|
95
|
+
result = value ?? true;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case "cancel": {
|
|
99
|
+
result = value ?? false;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
default: {
|
|
103
|
+
result = value;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Update the value
|
|
109
|
+
if (type !== "cancel") {
|
|
110
|
+
$state.value = result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Hide the popout
|
|
114
|
+
$state.visible = false;
|
|
115
|
+
|
|
116
|
+
// Call the callback
|
|
117
|
+
if ($props?.callback) {
|
|
118
|
+
$props?.callback(result);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function handleClickOutside(e: MouseEvent) {
|
|
123
|
+
e.preventDefault();
|
|
124
|
+
$state.visible = false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@render {
|
|
128
|
+
<div
|
|
129
|
+
{$props?.id}
|
|
130
|
+
class={["torp-select-box", $props?.class]}
|
|
131
|
+
{$props?.style}
|
|
132
|
+
>
|
|
133
|
+
<slot />
|
|
134
|
+
</div>
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { ClassValue, StyleValue } from "@torpor/view";
|
|
2
|
+
import { addDocumentEvent, removeDocumentEvent } from "../utils/documentEvents";
|
|
3
|
+
import { SelectBoxContextName, type SelectBoxContext } from "./SelectBoxTypes";
|
|
4
|
+
|
|
5
|
+
interface SelectBoxContentProps {
|
|
6
|
+
/** An ID for the root element */
|
|
7
|
+
id?: string;
|
|
8
|
+
/** Classes for the root element */
|
|
9
|
+
class?: ClassValue,
|
|
10
|
+
/** Styles for the root element */
|
|
11
|
+
style?: StyleValue,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The content that is displayed for a SelectBox when it is open, displayed
|
|
16
|
+
* alongside an element.
|
|
17
|
+
*/
|
|
18
|
+
export default function SelectBoxContent($props: SelectBoxContentProps | undefined) {
|
|
19
|
+
let div: HTMLDivElement;
|
|
20
|
+
let shown = false;
|
|
21
|
+
let closeOnClick = false;
|
|
22
|
+
|
|
23
|
+
// Get stuff out of the SelectBoxContext
|
|
24
|
+
const context = $context[SelectBoxContextName] as SelectBoxContext;
|
|
25
|
+
if (!context) {
|
|
26
|
+
throw new Error("SelectBoxContent must be contained within a SelectBox");
|
|
27
|
+
}
|
|
28
|
+
let $state = context.state;
|
|
29
|
+
|
|
30
|
+
$run(() => {
|
|
31
|
+
if (!$state.visible) {
|
|
32
|
+
hide();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function show() {
|
|
37
|
+
shown = true;
|
|
38
|
+
|
|
39
|
+
// HACK: Because this SelectBox could be shown with a click, we need to wait for another mousedown
|
|
40
|
+
// before we close on click. Otherwise the click immediately bubbles to the document
|
|
41
|
+
closeOnClick = false;
|
|
42
|
+
addDocumentEvent("mousedown", handleDocumentMouseDown);
|
|
43
|
+
addDocumentEvent("click", handleDocumentClick);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function hide() {
|
|
47
|
+
if (!shown) return;
|
|
48
|
+
|
|
49
|
+
removeDocumentEvent("mousedown", handleDocumentMouseDown);
|
|
50
|
+
removeDocumentEvent("click", handleDocumentClick);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleDocumentMouseDown() {
|
|
54
|
+
closeOnClick = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function handleDocumentClick(e: MouseEvent) {
|
|
58
|
+
if (
|
|
59
|
+
closeOnClick &&
|
|
60
|
+
div &&
|
|
61
|
+
!div.contains(e.target as HTMLElement)
|
|
62
|
+
) {
|
|
63
|
+
e.preventDefault();
|
|
64
|
+
context.handleClickOutside!(e);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@render {
|
|
69
|
+
@if ($state.visible) {
|
|
70
|
+
<div
|
|
71
|
+
{$props?.id}
|
|
72
|
+
class={["torp-select-box-content", $props?.class]}
|
|
73
|
+
{$props?.style}
|
|
74
|
+
&ref={div}
|
|
75
|
+
onmount={show}
|
|
76
|
+
>
|
|
77
|
+
<slot />
|
|
78
|
+
</div>
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { ClassValue, StyleValue } from "@torpor/view";
|
|
2
|
+
import { SelectBoxContextName, type SelectBoxContext } from "./SelectBoxTypes";
|
|
3
|
+
|
|
4
|
+
interface SelectBoxInputProps {
|
|
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 name of the input's form data field */
|
|
12
|
+
name?: string,
|
|
13
|
+
/** The value displayed in the input */
|
|
14
|
+
value?: any,
|
|
15
|
+
/** Text to display when the input value is empty */
|
|
16
|
+
placeholder?: string,
|
|
17
|
+
/** Whether the input's value is required */
|
|
18
|
+
required?: boolean,
|
|
19
|
+
/** An ARIA label for describing the input to screen readers when there is no associated label element */
|
|
20
|
+
ariaLabel?: string,
|
|
21
|
+
/** Raised on change */
|
|
22
|
+
onchange?: (e: Event) => void,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The input that causes a SelectBox to appear or disappear.
|
|
27
|
+
*/
|
|
28
|
+
export default function SelectBoxInput($props: SelectBoxInputProps | undefined) {
|
|
29
|
+
// Get stuff out of the SelectBoxContext
|
|
30
|
+
const context = $context[SelectBoxContextName] as SelectBoxContext;
|
|
31
|
+
if (!context) {
|
|
32
|
+
throw new Error("SelectBoxInput must be contained within a SelectBox");
|
|
33
|
+
}
|
|
34
|
+
let $state = context.state;
|
|
35
|
+
|
|
36
|
+
function handleClick() {
|
|
37
|
+
$state.visible = !$state.visible;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function handleKey(e: KeyboardEvent) {
|
|
41
|
+
switch (e.key) {
|
|
42
|
+
case "Down":
|
|
43
|
+
case "ArrowDown": {
|
|
44
|
+
if (!$state.visible) {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
$state.visible = true;
|
|
47
|
+
if (context.focusFirstElement) {
|
|
48
|
+
context.focusFirstElement();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "Up":
|
|
54
|
+
case "ArrowUp": {
|
|
55
|
+
if (!$state.visible) {
|
|
56
|
+
e.preventDefault();
|
|
57
|
+
$state.visible = true;
|
|
58
|
+
if (context.focusLastElement) {
|
|
59
|
+
context.focusLastElement();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
case "Escape": {
|
|
65
|
+
if ($state.visible) {
|
|
66
|
+
e.preventDefault();
|
|
67
|
+
$state.visible = false;
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@render {
|
|
75
|
+
<input
|
|
76
|
+
readonly
|
|
77
|
+
role="combobox"
|
|
78
|
+
{$props?.id}
|
|
79
|
+
class={["torp-select-box-input", $props?.class]}
|
|
80
|
+
{$props?.style}
|
|
81
|
+
{$props?.name}
|
|
82
|
+
{$props?.value}
|
|
83
|
+
{$props?.placeholder}
|
|
84
|
+
{$props?.required}
|
|
85
|
+
aria-readonly
|
|
86
|
+
aria-controls={$state.contentId}
|
|
87
|
+
aria-expanded={$state.visible ? "true" : "false"}
|
|
88
|
+
aria-label={$props?.ariaLabel}
|
|
89
|
+
onchange={$props?.onchange}
|
|
90
|
+
onclick={handleClick}
|
|
91
|
+
onkeydown={handleKey}
|
|
92
|
+
&ref={context.anchorElement}
|
|
93
|
+
/>
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ClassValue, StyleValue } from "@torpor/view";
|
|
2
|
+
import { SelectBoxContextName, type SelectBoxContext } from "./SelectBoxTypes";
|
|
3
|
+
|
|
4
|
+
interface SelectBoxTriggerProps {
|
|
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
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The button that causes a SelectBox to appear or disappear.
|
|
15
|
+
*/
|
|
16
|
+
export default function SelectBoxTrigger($props: SelectBoxTriggerProps | undefined) {
|
|
17
|
+
// Get stuff out of the SelectBoxContext
|
|
18
|
+
const context = $context[SelectBoxContextName] as SelectBoxContext;
|
|
19
|
+
if (!context) {
|
|
20
|
+
throw new Error("SelectBoxTrigger must be contained within a SelectBox");
|
|
21
|
+
}
|
|
22
|
+
let $state = context.state;
|
|
23
|
+
|
|
24
|
+
function handleClick() {
|
|
25
|
+
$state.visible = !$state.visible;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@render {
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
{$props?.id}
|
|
32
|
+
class={["torp-select-box-trigger", $props?.class]}
|
|
33
|
+
{$props?.style}
|
|
34
|
+
tabindex="-1"
|
|
35
|
+
onclick={handleClick}
|
|
36
|
+
&ref={context.anchorElement}
|
|
37
|
+
>
|
|
38
|
+
<slot />
|
|
39
|
+
</button>
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const SelectBoxContextName: unique symbol = Symbol.for("torp.SelectBox");
|
|
2
|
+
|
|
3
|
+
/** The shared context for modal components (Contextual, Prompt and SelectBox) */
|
|
4
|
+
export interface SelectBoxContext {
|
|
5
|
+
handleButton: (type: "confirm" | "cancel" | undefined, value?: any) => void;
|
|
6
|
+
// HACK: We need to be able to let children (i.e. Dialogs) override the click outside functionality
|
|
7
|
+
// There may be a more elegant way to accomplish this too
|
|
8
|
+
handleClickOutside?: (e: MouseEvent) => void;
|
|
9
|
+
state: SelectBoxState;
|
|
10
|
+
focusFirstElement?: () => void;
|
|
11
|
+
focusLastElement?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SelectBoxState {
|
|
15
|
+
visible: boolean;
|
|
16
|
+
value: any;
|
|
17
|
+
contentId?: string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { type SlotRender } from "@torpor/view";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
interface SelectBoxProps {
|
|
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 data value selected by the user */
|
|
12
|
+
value?: any,
|
|
13
|
+
/** Whether the popout is visible */
|
|
14
|
+
visible?: boolean,
|
|
15
|
+
/** A function to be called when the user selects a response */
|
|
16
|
+
callback?: ((value: any) => void),
|
|
17
|
+
/** Raised when the popout is opened or closed */
|
|
18
|
+
ontoggle?: (open: boolean) => void,
|
|
19
|
+
/** Raised when the popout has opened */
|
|
20
|
+
onopen?: () => void,
|
|
21
|
+
/** Raised when the popout has closed */
|
|
22
|
+
onclose?: (result: any) => void,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An input box for selecting a value from a popout ListBox or Dialog.
|
|
27
|
+
*
|
|
28
|
+
* See [the WAI ARIA guidelines for ComboBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
|
|
29
|
+
*
|
|
30
|
+
* The structure of a SelectBox is:
|
|
31
|
+
*
|
|
32
|
+
* ```
|
|
33
|
+
* <SelectBox>
|
|
34
|
+
* <SelectBoxInput />
|
|
35
|
+
* <SelectBoxTrigger /> (optional)
|
|
36
|
+
* <SelectBoxContent />
|
|
37
|
+
* </SelectBox>
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function SelectBox(
|
|
41
|
+
$parent: ParentNode,
|
|
42
|
+
$anchor: Node | null,
|
|
43
|
+
$props: SelectBoxProps | undefined,
|
|
44
|
+
$context?: Record<PropertyKey, any>,
|
|
45
|
+
$slots?: Record<string, SlotRender>,
|
|
46
|
+
): void;
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
interface SelectBoxContentProps {
|
|
51
|
+
/** An ID for the root element */
|
|
52
|
+
id?: string;
|
|
53
|
+
/** Classes for the root element */
|
|
54
|
+
class?: ClassValue,
|
|
55
|
+
/** Styles for the root element */
|
|
56
|
+
style?: StyleValue,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The content that is displayed for a SelectBox when it is open, displayed
|
|
61
|
+
* alongside an element.
|
|
62
|
+
*/
|
|
63
|
+
declare function SelectBoxContent(
|
|
64
|
+
$parent: ParentNode,
|
|
65
|
+
$anchor: Node | null,
|
|
66
|
+
$props: SelectBoxContentProps | undefined,
|
|
67
|
+
$context?: Record<PropertyKey, any>,
|
|
68
|
+
$slots?: Record<string, SlotRender>,
|
|
69
|
+
): void;
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
interface SelectBoxInputProps {
|
|
74
|
+
/** An ID for the root element */
|
|
75
|
+
id?: string;
|
|
76
|
+
/** Classes for the root element */
|
|
77
|
+
class?: ClassValue,
|
|
78
|
+
/** Styles for the root element */
|
|
79
|
+
style?: StyleValue,
|
|
80
|
+
/** The name of the input's form data field */
|
|
81
|
+
name?: string,
|
|
82
|
+
/** The value displayed in the input */
|
|
83
|
+
value?: any,
|
|
84
|
+
/** Text to display when the input value is empty */
|
|
85
|
+
placeholder?: string,
|
|
86
|
+
/** Whether the input's value is required */
|
|
87
|
+
required?: boolean,
|
|
88
|
+
/** An ARIA label for describing the input to screen readers when there is no associated label element */
|
|
89
|
+
ariaLabel?: string,
|
|
90
|
+
/** Raised on change */
|
|
91
|
+
onchange?: (e: Event) => void,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The input that causes a SelectBox to appear or disappear.
|
|
96
|
+
*/
|
|
97
|
+
declare function SelectBoxInput(
|
|
98
|
+
$parent: ParentNode,
|
|
99
|
+
$anchor: Node | null,
|
|
100
|
+
$props: SelectBoxInputProps | undefined,
|
|
101
|
+
$context?: Record<PropertyKey, any>,
|
|
102
|
+
$slots?: Record<string, SlotRender>,
|
|
103
|
+
): void;
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
interface SelectBoxTriggerProps {
|
|
108
|
+
/** An ID for the root element */
|
|
109
|
+
id?: string;
|
|
110
|
+
/** Classes for the root element */
|
|
111
|
+
class?: ClassValue,
|
|
112
|
+
/** Styles for the root element */
|
|
113
|
+
style?: StyleValue,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The button that causes a SelectBox to appear or disappear.
|
|
118
|
+
*/
|
|
119
|
+
declare function SelectBoxTrigger(
|
|
120
|
+
$parent: ParentNode,
|
|
121
|
+
$anchor: Node | null,
|
|
122
|
+
$props: SelectBoxTriggerProps | undefined,
|
|
123
|
+
$context?: Record<PropertyKey, any>,
|
|
124
|
+
$slots?: Record<string, SlotRender>,
|
|
125
|
+
): void;
|
|
126
|
+
|
|
127
|
+
export { SelectBox, SelectBoxContent, SelectBoxInput, SelectBoxTrigger };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// src/SelectBox/SelectBox.torp
|
|
2
|
+
import SelectBox_default from "./SelectBox.torp";
|
|
3
|
+
|
|
4
|
+
// src/SelectBox/SelectBoxContent.torp
|
|
5
|
+
import SelectBoxContent_default from "./SelectBoxContent.torp";
|
|
6
|
+
|
|
7
|
+
// src/SelectBox/SelectBoxInput.torp
|
|
8
|
+
import SelectBoxInput_default from "./SelectBoxInput.torp";
|
|
9
|
+
|
|
10
|
+
// src/SelectBox/SelectBoxTrigger.torp
|
|
11
|
+
import SelectBoxTrigger_default from "./SelectBoxTrigger.torp";
|
|
12
|
+
export {
|
|
13
|
+
SelectBox_default as SelectBox,
|
|
14
|
+
SelectBoxContent_default as SelectBoxContent,
|
|
15
|
+
SelectBoxInput_default as SelectBoxInput,
|
|
16
|
+
SelectBoxTrigger_default as SelectBoxTrigger
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -90,12 +90,12 @@ export default function TabGroup($props: TabGroupProps | undefined) {
|
|
|
90
90
|
// Dispatch the change event when the value changes
|
|
91
91
|
let firstChange = true;
|
|
92
92
|
$run(() => {
|
|
93
|
-
const
|
|
93
|
+
const onchange = $props?.onchange;
|
|
94
94
|
const value = $props?.value;
|
|
95
95
|
if (firstChange) {
|
|
96
96
|
firstChange = false;
|
|
97
|
-
} else if (
|
|
98
|
-
|
|
97
|
+
} else if (onchange) {
|
|
98
|
+
onchange(value!);
|
|
99
99
|
}
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const TabGroupContextName = "TabGroup";
|
|
2
|
-
export const TabItemContextName = "TabItem";
|
|
1
|
+
export const TabGroupContextName: unique symbol = Symbol.for("torp.TabGroup");
|
|
2
|
+
export const TabItemContextName: unique symbol = Symbol.for("torp.TabItem");
|
|
3
3
|
|
|
4
4
|
export interface TabGroupContext {
|
|
5
5
|
/** Called from a header when it is added */
|