@torpor/ui 0.1.7 → 0.2.1
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 +47 -0
- package/dist/Accordion/Accordion.torp +25 -13
- package/dist/Accordion/AccordionContent.torp +15 -8
- package/dist/Accordion/AccordionHeader.torp +16 -7
- package/dist/Accordion/AccordionItem.torp +24 -10
- package/dist/Accordion/AccordionTrigger.torp +16 -8
- package/dist/Accordion/AccordionTypes.ts +2 -0
- package/dist/Accordion/index.d.ts +157 -0
- package/dist/Breadcrumb/Breadcrumb.torp +42 -0
- package/dist/Breadcrumb/BreadcrumbItem.torp +28 -0
- package/dist/Breadcrumb/BreadcrumbSeparator.torp +25 -0
- package/dist/Breadcrumb/index.d.ts +84 -0
- package/dist/Breadcrumb/index.js +14 -0
- package/dist/Calendar/Calendar.torp +273 -0
- package/dist/Calendar/CalendarDay.torp +75 -0
- package/dist/Calendar/CalendarTypes.ts +22 -0
- package/dist/Calendar/index.d.ts +36 -0
- package/dist/Calendar/index.js +10 -0
- package/dist/Calendar/index.js.map +1 -0
- package/dist/Dialog/Dialog.torp +16 -6
- package/dist/Dialog/DialogBody.torp +13 -5
- package/dist/Dialog/DialogButton.torp +18 -6
- package/dist/Dialog/DialogFooter.torp +13 -3
- package/dist/Dialog/DialogHeader.torp +13 -4
- package/dist/Dialog/index.d.ts +135 -0
- package/dist/Disclosure/Disclosure.torp +79 -0
- package/dist/Disclosure/DisclosureContent.torp +43 -0
- package/dist/Disclosure/DisclosureHeader.torp +43 -0
- package/dist/Disclosure/DisclosureTrigger.torp +44 -0
- package/dist/Disclosure/DisclosureTypes.ts +14 -0
- package/dist/Disclosure/index.d.ts +113 -0
- package/dist/Disclosure/index.js +18 -0
- package/dist/Disclosure/index.js.map +1 -0
- package/{src/Offscreen/Offscreen.torp → dist/Drawer/Drawer.torp} +20 -19
- package/dist/Drawer/index.d.ts +21 -0
- package/dist/Drawer/index.js +6 -0
- package/dist/Drawer/index.js.map +1 -0
- package/dist/Form/Field.torp +93 -0
- package/dist/Form/Form.torp +131 -0
- package/dist/Form/FormTypes.ts +30 -0
- package/dist/Form/Input.torp +94 -0
- package/dist/Form/Label.torp +31 -0
- package/dist/Form/Message.torp +35 -0
- package/dist/Form/StandardSchemaV1.ts +70 -0
- package/dist/Form/index.d.ts +117 -0
- package/dist/Form/index.js +22 -0
- package/dist/Form/index.js.map +1 -0
- package/dist/Menu/Menu.torp +169 -0
- package/dist/Menu/MenuButton.torp +64 -0
- package/dist/Menu/MenuCheck.torp +81 -0
- package/dist/Menu/MenuGroup.torp +29 -0
- package/dist/Menu/MenuIndicator.torp +38 -0
- package/dist/Menu/MenuPopout.torp +82 -0
- package/dist/Menu/MenuPopoutContent.torp +83 -0
- package/dist/Menu/MenuPopoutTrigger.torp +126 -0
- package/dist/Menu/MenuRadio.torp +99 -0
- package/dist/Menu/MenuRadioGroup.torp +97 -0
- package/dist/Menu/MenuSeparator.torp +24 -0
- package/dist/Menu/MenuTypes.ts +58 -0
- package/dist/Menu/index.d.ts +293 -0
- package/dist/Menu/index.js +46 -0
- package/dist/Menu/index.js.map +1 -0
- package/dist/MenuBar/MenuBar.torp +159 -0
- package/dist/MenuBar/MenuBarItem.torp +115 -0
- package/dist/MenuBar/MenuBarItemContent.torp +117 -0
- package/dist/MenuBar/MenuBarItemTrigger.torp +98 -0
- package/dist/MenuBar/MenuBarTypes.ts +36 -0
- package/dist/MenuBar/index.d.ts +125 -0
- package/dist/MenuBar/index.js +18 -0
- package/dist/MenuBar/index.js.map +1 -0
- package/dist/NavMenu/NavMenu.torp +15 -6
- package/dist/NavMenu/NavMenuButton.torp +14 -7
- package/dist/NavMenu/NavMenuElement.torp +16 -8
- package/dist/NavMenu/NavMenuGroup.torp +14 -5
- package/dist/NavMenu/NavMenuGroupHeader.torp +14 -6
- package/dist/NavMenu/NavMenuLink.torp +18 -10
- package/dist/NavMenu/NavMenuPopout.torp +13 -5
- package/dist/NavMenu/NavMenuPopoutButton.torp +17 -11
- package/dist/NavMenu/NavMenuPopoutContent.torp +42 -30
- package/dist/NavMenu/NavMenuSeparator.torp +12 -3
- package/dist/NavMenu/index.d.ts +259 -0
- package/dist/Notification/Notification.torp +58 -0
- package/dist/Notification/NotificationClose.torp +37 -0
- package/dist/Notification/NotificationContainer.torp +24 -0
- package/dist/Notification/NotificationContent.torp +23 -0
- package/dist/Notification/NotificationTypes.ts +5 -0
- package/dist/Notification/index.d.ts +92 -0
- package/dist/Notification/index.js +36 -0
- package/dist/Notification/index.js.map +1 -0
- package/dist/Notification/showNotification.ts +30 -0
- package/dist/Popover/Popover.torp +22 -8
- package/dist/Popover/PopoverContent.torp +41 -29
- package/dist/Popover/PopoverContentAnchored.torp +52 -44
- package/dist/Popover/PopoverContentContextual.torp +49 -37
- package/dist/Popover/PopoverOverlay.torp +13 -4
- package/dist/Popover/PopoverTrigger.torp +12 -3
- package/dist/Popover/PopoverTriggerContextual.torp +12 -3
- package/dist/Popover/PopoverTriggerHover.torp +14 -5
- package/dist/Popover/index.d.ts +191 -0
- package/dist/TabGroup/TabContent.torp +13 -7
- package/dist/TabGroup/TabGroup.torp +23 -11
- package/dist/TabGroup/TabHeader.torp +16 -7
- package/dist/TabGroup/TabList.torp +15 -6
- package/dist/TabGroup/TabTrigger.torp +14 -6
- package/dist/TabGroup/index.d.ts +150 -0
- package/dist/icons/ArrowDown.torp +15 -0
- package/dist/icons/ArrowLeft.torp +15 -0
- package/dist/icons/ArrowRight.torp +15 -0
- package/dist/icons/ArrowUp.torp +15 -0
- package/dist/icons/Bars.torp +17 -0
- package/dist/icons/Check.torp +15 -0
- package/dist/icons/ChevronDown.torp +15 -0
- package/dist/icons/ChevronLeft.torp +15 -0
- package/dist/icons/ChevronRight.torp +15 -0
- package/dist/icons/ChevronUp.torp +15 -0
- package/dist/icons/Cross.torp +16 -0
- package/dist/icons/Loading.torp +16 -0
- package/dist/icons/Minus.torp +15 -0
- package/dist/icons/Plus.torp +16 -0
- package/dist/icons/index.d.ts +142 -0
- package/dist/icons/index.js +58 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/{motion.d.cts → index.d.ts} +2 -2
- package/dist/metafile-esm.json +1 -1
- package/dist/motion/fade.ts +7 -0
- package/dist/motion/index.d.ts +2 -0
- package/dist/{motion.js → motion/index.js} +1 -1
- package/dist/motion/index.js.map +1 -0
- package/dist/mount/index.d.ts +2 -0
- package/dist/utils/dateUtils.ts +244 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/setPopoverPosition.ts +4 -0
- package/package.json +60 -35
- package/scripts/postbuild.ts +42 -5
- package/src/Accordion/Accordion.torp +25 -13
- package/src/Accordion/AccordionContent.torp +15 -8
- package/src/Accordion/AccordionHeader.torp +16 -7
- package/src/Accordion/AccordionItem.torp +24 -10
- package/src/Accordion/AccordionTrigger.torp +16 -8
- package/src/Accordion/AccordionTypes.ts +2 -0
- package/src/Breadcrumb/Breadcrumb.torp +42 -0
- package/src/Breadcrumb/BreadcrumbItem.torp +28 -0
- package/src/Breadcrumb/BreadcrumbSeparator.torp +25 -0
- package/src/Breadcrumb/index.ts +5 -0
- package/src/Calendar/Calendar.torp +273 -0
- package/src/Calendar/CalendarDay.torp +75 -0
- package/src/Calendar/CalendarTypes.ts +22 -0
- package/src/Calendar/index.ts +4 -0
- package/src/Dialog/Dialog.torp +16 -6
- package/src/Dialog/DialogBody.torp +13 -5
- package/src/Dialog/DialogButton.torp +18 -6
- package/src/Dialog/DialogFooter.torp +13 -3
- package/src/Dialog/DialogHeader.torp +13 -4
- package/src/Disclosure/Disclosure.torp +79 -0
- package/src/Disclosure/DisclosureContent.torp +43 -0
- package/src/Disclosure/DisclosureHeader.torp +43 -0
- package/src/Disclosure/DisclosureTrigger.torp +44 -0
- package/src/Disclosure/DisclosureTypes.ts +14 -0
- package/src/Disclosure/index.ts +6 -0
- package/{dist/Offscreen/Offscreen.torp → src/Drawer/Drawer.torp} +20 -19
- package/src/Drawer/index.ts +3 -0
- package/src/Form/Field.torp +93 -0
- package/src/Form/Form.torp +131 -0
- package/src/Form/FormTypes.ts +30 -0
- package/src/Form/Input.torp +94 -0
- package/src/Form/Label.torp +31 -0
- package/src/Form/Message.torp +35 -0
- package/src/Form/StandardSchemaV1.ts +70 -0
- package/src/Form/index.ts +7 -0
- package/src/Menu/Menu.torp +169 -0
- package/src/Menu/MenuButton.torp +64 -0
- package/src/Menu/MenuCheck.torp +81 -0
- package/src/Menu/MenuGroup.torp +29 -0
- package/src/Menu/MenuIndicator.torp +38 -0
- package/src/Menu/MenuPopout.torp +82 -0
- package/src/Menu/MenuPopoutContent.torp +83 -0
- package/src/Menu/MenuPopoutTrigger.torp +126 -0
- package/src/Menu/MenuRadio.torp +99 -0
- package/src/Menu/MenuRadioGroup.torp +97 -0
- package/src/Menu/MenuSeparator.torp +24 -0
- package/src/Menu/MenuTypes.ts +58 -0
- package/src/Menu/index.ts +25 -0
- package/src/MenuBar/MenuBar.torp +159 -0
- package/src/MenuBar/MenuBarItem.torp +115 -0
- package/src/MenuBar/MenuBarItemContent.torp +117 -0
- package/src/MenuBar/MenuBarItemTrigger.torp +98 -0
- package/src/MenuBar/MenuBarTypes.ts +36 -0
- package/src/MenuBar/index.ts +6 -0
- package/src/NavMenu/NavMenu.torp +15 -6
- package/src/NavMenu/NavMenuButton.torp +14 -7
- package/src/NavMenu/NavMenuElement.torp +16 -8
- package/src/NavMenu/NavMenuGroup.torp +14 -5
- package/src/NavMenu/NavMenuGroupHeader.torp +14 -6
- package/src/NavMenu/NavMenuLink.torp +18 -10
- package/src/NavMenu/NavMenuPopout.torp +13 -5
- package/src/NavMenu/NavMenuPopoutButton.torp +17 -11
- package/src/NavMenu/NavMenuPopoutContent.torp +42 -30
- package/src/NavMenu/NavMenuSeparator.torp +12 -3
- package/src/Notification/Notification.torp +58 -0
- package/src/Notification/NotificationClose.torp +37 -0
- package/src/Notification/NotificationContainer.torp +24 -0
- package/src/Notification/NotificationContent.torp +23 -0
- package/src/Notification/NotificationTypes.ts +5 -0
- package/src/Notification/index.ts +13 -0
- package/src/Notification/showNotification.ts +30 -0
- package/src/Popover/Popover.torp +22 -8
- package/src/Popover/PopoverContent.torp +41 -29
- package/src/Popover/PopoverContentAnchored.torp +52 -44
- package/src/Popover/PopoverContentContextual.torp +49 -37
- package/src/Popover/PopoverOverlay.torp +13 -4
- package/src/Popover/PopoverTrigger.torp +12 -3
- package/src/Popover/PopoverTriggerContextual.torp +12 -3
- package/src/Popover/PopoverTriggerHover.torp +14 -5
- package/src/Slider/Slider.torp +83 -0
- package/src/Slider/index.ts +3 -0
- package/src/TabGroup/TabContent.torp +13 -7
- package/src/TabGroup/TabGroup.torp +23 -11
- package/src/TabGroup/TabHeader.torp +16 -7
- package/src/TabGroup/TabList.torp +15 -6
- package/src/TabGroup/TabTrigger.torp +14 -6
- package/src/icons/ArrowDown.torp +15 -0
- package/src/icons/ArrowLeft.torp +15 -0
- package/src/icons/ArrowRight.torp +15 -0
- package/src/icons/ArrowUp.torp +15 -0
- package/src/icons/Bars.torp +17 -0
- package/src/icons/Check.torp +15 -0
- package/src/icons/ChevronDown.torp +15 -0
- package/src/icons/ChevronLeft.torp +15 -0
- package/src/icons/ChevronRight.torp +15 -0
- package/src/icons/ChevronUp.torp +15 -0
- package/src/icons/Cross.torp +16 -0
- package/src/icons/Loading.torp +16 -0
- package/src/icons/Minus.torp +15 -0
- package/src/icons/Plus.torp +16 -0
- package/src/icons/index.ts +31 -0
- package/src/motion/fade.ts +2 -2
- package/src/motion/index.ts +3 -0
- package/src/utils/dateUtils.ts +244 -0
- package/src/utils/setPopoverPosition.ts +4 -0
- package/test/Accordion/components/AccordionAccessibility.torp +2 -0
- package/test/Accordion/components/AccordionKeyboard.torp +2 -0
- package/test/Accordion/components/AccordionList.torp +2 -0
- package/test/Accordion/components/AccordionMultiple.torp +2 -0
- package/test/Accordion/components/AccordionSingle.torp +2 -0
- package/test/Breadcrumb/accessibility.test.ts +29 -0
- package/test/Breadcrumb/basic.test.ts +17 -0
- package/test/Breadcrumb/components/BreadcrumbTest.torp +15 -0
- package/test/Calendar/components/CalendarTest.torp +9 -0
- package/test/Calendar/default.test.ts +18 -0
- package/test/Dialog/components/DialogAccessibility.torp +5 -5
- package/test/Disclosure/accessibility.test.ts +31 -0
- package/test/Disclosure/components/DisclosureTest.torp +19 -0
- package/test/Disclosure/default.test.ts +15 -0
- package/test/Disclosure/toggle.test.ts +20 -0
- package/test/Form/components/FieldTest.torp +25 -0
- package/test/Form/components/FormTest.torp +31 -0
- package/test/Form/components/InputTest.torp +9 -0
- package/test/Form/field.test.ts +34 -0
- package/test/Form/form.test.ts +34 -0
- package/test/Form/input.test.ts +19 -0
- package/test/Menu/accessibility.test.ts +83 -0
- package/test/Menu/basic.test.ts +58 -0
- package/test/Menu/components/MenuAccessibility.torp +59 -0
- package/test/Menu/components/MenuBasic.torp +58 -0
- package/test/MenuBar/accessibility.test.ts +87 -0
- package/test/MenuBar/basic.test.ts +22 -0
- package/test/MenuBar/components/MenuBarAccessibility.torp +34 -0
- package/test/MenuBar/components/MenuBarBasic.torp +25 -0
- package/test/NavMenu/basic.test.ts +1 -1
- package/test/NavMenu/components/{NavMenu.torp → NavMenuBasic.torp} +1 -1
- package/test/Notification/accessibility.test.ts +21 -0
- package/test/Notification/components/CustomNotification.torp +14 -0
- package/test/Notification/components/NotificationAccessibility.torp +14 -0
- package/test/Notification/components/NotificationFunction.torp +20 -0
- package/test/Notification/components/NotificationVariable.torp +22 -0
- package/test/Notification/function.test.ts +25 -0
- package/test/Notification/variable.test.ts +25 -0
- package/test/Popover/components/CustomDialog.torp +25 -0
- package/test/Popover/components/PromptFunction.torp +19 -0
- package/test/Popover/components/PromptVariable.torp +38 -0
- package/test/Popover/function.test.ts +26 -0
- package/test/Popover/variable.test.ts +27 -0
- package/test/TabGroup/components/TabGroupAccessibility.torp +2 -0
- package/test/TabGroup/components/TabGroupKeyboard.torp +2 -0
- package/test/TabGroup/components/TabGroupList.torp +2 -0
- package/test/TabGroup/components/TabGroupTrigger.torp +2 -0
- package/tsup.config.ts +12 -4
- package/dist/Accordion/index.cjs +0 -53
- package/dist/Accordion/index.cjs.map +0 -1
- package/dist/Dialog/index.cjs +0 -53
- package/dist/Dialog/index.cjs.map +0 -1
- package/dist/NavMenu/index.cjs +0 -78
- package/dist/NavMenu/index.cjs.map +0 -1
- package/dist/Offscreen/index.cjs +0 -33
- package/dist/Offscreen/index.cjs.map +0 -1
- package/dist/Offscreen/index.js +0 -6
- package/dist/Popover/index.cjs +0 -222
- package/dist/Popover/index.cjs.map +0 -1
- package/dist/TabGroup/index.cjs +0 -53
- package/dist/TabGroup/index.cjs.map +0 -1
- package/dist/metafile-cjs.json +0 -1
- package/dist/motion.cjs +0 -34
- package/dist/motion.cjs.map +0 -1
- package/dist/motion.d.ts +0 -6
- package/dist/motion.js.map +0 -1
- package/src/Accordion.ts +0 -7
- package/src/Dialog.ts +0 -7
- package/src/NavMenu.ts +0 -23
- package/src/Offscreen/index.ts +0 -3
- package/src/Popover.ts +0 -29
- package/src/TabGroup.ts +0 -7
- package/src/motion.ts +0 -3
- /package/dist/{Offscreen → Breadcrumb}/index.js.map +0 -0
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import getId from "../utils/getId";
|
|
2
2
|
import { DialogContextName, type DialogContext } from "./DialogTypes";
|
|
3
3
|
|
|
4
|
+
interface DialogBodyProps {
|
|
5
|
+
/** An ID for the root element */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Class name(s) for the root element */
|
|
8
|
+
class?: string,
|
|
9
|
+
/** Whether the body content will be announced by screen readers when the Dialog is opened */
|
|
10
|
+
ariaAnnounce?: boolean,
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* The body information for a Dialog. Content in the body will be announced by
|
|
6
15
|
* screen readers when the Dialog is opened, unless ariaAnnounce is false.
|
|
7
|
-
*
|
|
8
|
-
* @prop {boolean} ariaAnnounce -- Whether the body content will be announced by screen readers when the Dialog is opened
|
|
9
16
|
*/
|
|
10
|
-
export default function DialogBody($props:
|
|
17
|
+
export default function DialogBody($props: DialogBodyProps) {
|
|
18
|
+
$props ??= $watch({});
|
|
11
19
|
$props.id ??= getId();
|
|
12
20
|
$props.ariaAnnounce ??= true;
|
|
13
21
|
|
|
@@ -25,10 +33,10 @@ export default function DialogBody($props: any) {
|
|
|
25
33
|
|
|
26
34
|
@render {
|
|
27
35
|
<div
|
|
28
|
-
|
|
36
|
+
{$props.id}
|
|
29
37
|
class={`torp-dialog-body ${$props.class ?? ""}`.trim()}
|
|
30
38
|
>
|
|
31
|
-
|
|
39
|
+
<slot />
|
|
32
40
|
</div>
|
|
33
41
|
}
|
|
34
42
|
}
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { DialogContextName, type DialogContext } from "./DialogTypes";
|
|
2
2
|
|
|
3
|
+
interface DialogButtonProps {
|
|
4
|
+
/** An ID for the root element */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Class name(s) for the root element */
|
|
7
|
+
class?: string,
|
|
8
|
+
/** The value that should be returned when this button is pressed and the Dialog was invoked by calling showContextual, showPrompt or showPopover */
|
|
9
|
+
value?: any,
|
|
10
|
+
/** "confirm" if the button should respond to the Enter key or "cancel" if the button should respond to the Escape key */
|
|
11
|
+
type?: "confirm" | "cancel",
|
|
12
|
+
/** Whether this button is disabled */
|
|
13
|
+
disabled?: boolean,
|
|
14
|
+
}
|
|
15
|
+
|
|
3
16
|
/**
|
|
4
17
|
* A button that is placed in a DialogFooter and signals a response by a user.
|
|
5
18
|
*
|
|
6
|
-
* @prop {any | undefined} value -- The value that should be returned when this button is pressed and the Dialog was invoked by calling showContextual, showPrompt or showPopover
|
|
7
|
-
* @prop {"confirm" | "cancel" | undefined} type -- "confirm" if the button should respond to the Enter key or "cancel" if the button should respond to the Escape key
|
|
8
|
-
* @prop {boolean} disabled -- Whether this button is disabled
|
|
9
19
|
*/
|
|
10
|
-
export default function DialogButton($props:
|
|
20
|
+
export default function DialogButton($props: DialogButtonProps) {
|
|
21
|
+
$props ??= $watch({});
|
|
22
|
+
|
|
11
23
|
let button: HTMLButtonElement;
|
|
12
24
|
|
|
13
25
|
// Get stuff out of the DialogContext
|
|
@@ -36,13 +48,13 @@ export default function DialogButton($props: any) {
|
|
|
36
48
|
@render {
|
|
37
49
|
<button
|
|
38
50
|
type="button"
|
|
39
|
-
|
|
51
|
+
{$props.id}
|
|
40
52
|
class={`torp-dialog-button ${$props.class ?? ""}`.trim()}
|
|
41
53
|
disabled={$props.disabled}
|
|
42
54
|
onclick={handleClick}
|
|
43
55
|
&ref={button}
|
|
44
56
|
>
|
|
45
|
-
|
|
57
|
+
<slot />
|
|
46
58
|
</button>
|
|
47
59
|
}
|
|
48
60
|
}
|
|
@@ -1,13 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
interface DialogFooterProps {
|
|
3
|
+
/** An ID for the root element */
|
|
4
|
+
id?: string;
|
|
5
|
+
/** Class name(s) for the root element */
|
|
6
|
+
class?: string,
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
/**
|
|
2
10
|
* The footer for a Dialog, which may contain one or more DialogButtons.
|
|
3
11
|
*/
|
|
4
|
-
export default function DialogFooter($props:
|
|
12
|
+
export default function DialogFooter($props: DialogFooterProps) {
|
|
13
|
+
$props ??= $watch({});
|
|
14
|
+
|
|
5
15
|
@render {
|
|
6
16
|
<div
|
|
7
|
-
|
|
17
|
+
{$props.id}
|
|
8
18
|
class={`torp-dialog-footer ${$props.class ?? ""}`.trim()}
|
|
9
19
|
>
|
|
10
|
-
|
|
20
|
+
<slot />
|
|
11
21
|
</div>
|
|
12
22
|
}
|
|
13
23
|
}
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import getId from "../utils/getId";
|
|
2
2
|
import { DialogContextName, type DialogContext } from "./DialogTypes";
|
|
3
3
|
|
|
4
|
+
interface DialogHeaderProps {
|
|
5
|
+
/** An ID for the root element */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Class name(s) for the root element */
|
|
8
|
+
class?: string,
|
|
9
|
+
/** Whether the header will be announced by screen readers when the Dialog is opened */
|
|
10
|
+
ariaAnnounce?: boolean,
|
|
11
|
+
}
|
|
12
|
+
|
|
4
13
|
/**
|
|
5
14
|
* The header for a Dialog. Content in the header will be announced by screen
|
|
6
15
|
* readers when the Dialog is opened, unless ariaAnnounce is false.
|
|
7
16
|
*
|
|
8
|
-
* @prop {boolean} ariaAnnounce -- Whether the header will be announced by screen readers when the Dialog is opened
|
|
9
17
|
*/
|
|
10
|
-
export default function DialogHeader($props:
|
|
18
|
+
export default function DialogHeader($props: DialogHeaderProps) {
|
|
19
|
+
$props ??= $watch({});
|
|
11
20
|
$props.id ??= getId();
|
|
12
21
|
$props.ariaAnnounce ??= true;
|
|
13
22
|
|
|
@@ -25,10 +34,10 @@ export default function DialogHeader($props: any) {
|
|
|
25
34
|
|
|
26
35
|
@render {
|
|
27
36
|
<div
|
|
28
|
-
|
|
37
|
+
{$props.id}
|
|
29
38
|
class={`torp-dialog-footer ${$props.class ?? ""}`.trim()}
|
|
30
39
|
>
|
|
31
|
-
|
|
40
|
+
<slot />
|
|
32
41
|
</div>
|
|
33
42
|
}
|
|
34
43
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { DisclosureContextName, type DisclosureContext, type DisclosureState } from "./DisclosureTypes";
|
|
2
|
+
|
|
3
|
+
interface DisclosureProps {
|
|
4
|
+
/** An ID for the root element */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Class name(s) for the root element */
|
|
7
|
+
class?: string,
|
|
8
|
+
/** Whether the Disclosure is expanded and its content visible */
|
|
9
|
+
expanded?: boolean,
|
|
10
|
+
/** If set to true, the user cannot interact with this Disclosure */
|
|
11
|
+
disabled?: boolean,
|
|
12
|
+
/** Raised when this item is opened or closed */
|
|
13
|
+
ontoggle?: (open: boolean) => void,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An interactive header that enables users to reveal or hide an associated section of content.
|
|
18
|
+
*
|
|
19
|
+
* See [the WAI ARIA guidelines for Disclosures](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/).
|
|
20
|
+
*
|
|
21
|
+
* The structure of a Disclosure is:
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
* <Disclosure>
|
|
25
|
+
* <DisclosureHeader>
|
|
26
|
+
* <DisclosureTrigger />
|
|
27
|
+
* </DisclosureHeader>
|
|
28
|
+
* <DisclosureContent />
|
|
29
|
+
* </Disclosure>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export default function Disclosure($props: DisclosureProps) {
|
|
33
|
+
$props ??= $watch({});
|
|
34
|
+
$props.expanded ??= false;
|
|
35
|
+
$props.disabled ??= false;
|
|
36
|
+
|
|
37
|
+
let $state: DisclosureState = $watch({
|
|
38
|
+
expanded: $props.expanded && $props.expanded !== "false",
|
|
39
|
+
disabled: $props.disabled,
|
|
40
|
+
get dataState() {
|
|
41
|
+
return this.expanded ? "open" : "closed";
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Update $state with $props
|
|
46
|
+
$run(() => {
|
|
47
|
+
$state.expanded = $props.expanded && $props.expanded !== "false";
|
|
48
|
+
$state.disabled = $props.disabled;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Put stuff into a DisclosureContext
|
|
52
|
+
const itemContext: DisclosureContext = {
|
|
53
|
+
state: $state,
|
|
54
|
+
};
|
|
55
|
+
$context[DisclosureContextName] = itemContext;
|
|
56
|
+
|
|
57
|
+
// Dispatch the toggle event when the value of expanded changes
|
|
58
|
+
let firstToggle = true;
|
|
59
|
+
$run(() => {
|
|
60
|
+
const ev = $props.ontoggle;
|
|
61
|
+
const expanded = $state.expanded;
|
|
62
|
+
if (firstToggle) {
|
|
63
|
+
firstToggle = false;
|
|
64
|
+
} else if (ev) {
|
|
65
|
+
ev(expanded);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
@render {
|
|
70
|
+
<div
|
|
71
|
+
{$props.id}
|
|
72
|
+
class={`torp-disclosure-item ${$props.class ?? ""}`.trim()}
|
|
73
|
+
data-state={$state.dataState}
|
|
74
|
+
data-disabled={$state.disabled ? "true" : undefined}
|
|
75
|
+
>
|
|
76
|
+
<slot />
|
|
77
|
+
</div>
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import getId from "../utils/getId";
|
|
2
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
3
|
+
|
|
4
|
+
interface DisclosureContentProps {
|
|
5
|
+
/** An ID for the root element */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Class name(s) for the root element */
|
|
8
|
+
class?: string,
|
|
9
|
+
/** Whether this content should act as a region. Set this when the content contains heading elements or a nested Disclosure */
|
|
10
|
+
ariaRegion?: boolean,
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Content for a Disclosure, which can be revealed or hidden by an associated DisclosureTrigger.
|
|
15
|
+
*/
|
|
16
|
+
export default function DisclosureContent($props: DisclosureContentProps) {
|
|
17
|
+
$props ??= $watch({});
|
|
18
|
+
$props.id ||= getId();
|
|
19
|
+
|
|
20
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
21
|
+
if (!context) {
|
|
22
|
+
throw new Error("DisclosureContent must be contained within a Disclosure");
|
|
23
|
+
}
|
|
24
|
+
let $state = context.state
|
|
25
|
+
|
|
26
|
+
// Set the content ID so that it can be used with aria-controls in DisclosureTrigger
|
|
27
|
+
$state.contentId = $props.id;
|
|
28
|
+
|
|
29
|
+
@render {
|
|
30
|
+
<div
|
|
31
|
+
{$props.id}
|
|
32
|
+
class={`torp-disclosure-content ${$props.class ?? ""}`.trim()}
|
|
33
|
+
role={$props.ariaRegion ? "region" : undefined}
|
|
34
|
+
aria-labelledby={$state.headerId}
|
|
35
|
+
data-state={$state.dataState}
|
|
36
|
+
data-disabled={$state.disabled ? "true" : undefined}
|
|
37
|
+
>
|
|
38
|
+
@if ($state.expanded) {
|
|
39
|
+
<slot />
|
|
40
|
+
}
|
|
41
|
+
</div>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
2
|
+
|
|
3
|
+
interface DisclosureHeaderProps {
|
|
4
|
+
/** An ID for the root element */
|
|
5
|
+
id?: string;
|
|
6
|
+
/** Class name(s) for the root element */
|
|
7
|
+
class?: string,
|
|
8
|
+
/** The type of HTML header to use */
|
|
9
|
+
as?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The header for a Disclosure, which contains the DisclosureTrigger.
|
|
14
|
+
*
|
|
15
|
+
* The structure of a DisclosureHeader is:
|
|
16
|
+
*
|
|
17
|
+
* ```
|
|
18
|
+
* <DisclosureHeader>
|
|
19
|
+
* <DisclosureTrigger />
|
|
20
|
+
* </DisclosureHeader>
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export default function DisclosureHeader($props: DisclosureHeaderProps) {
|
|
24
|
+
$props ??= $watch({});
|
|
25
|
+
|
|
26
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
27
|
+
if (!context) {
|
|
28
|
+
throw new Error("DisclosureHeader must be contained within a Disclosure");
|
|
29
|
+
}
|
|
30
|
+
let $state = context.state
|
|
31
|
+
|
|
32
|
+
@render {
|
|
33
|
+
@// TODO: $props.as
|
|
34
|
+
<h4
|
|
35
|
+
{$props.id}
|
|
36
|
+
class={`torp-disclosure-header ${$props.class ?? ""}`.trim()}
|
|
37
|
+
data-state={$state.dataState}
|
|
38
|
+
data-disabled={$state.disabled ? "true" : undefined}
|
|
39
|
+
>
|
|
40
|
+
<slot />
|
|
41
|
+
</h4>
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import getId from "../utils/getId";
|
|
2
|
+
import { DisclosureContextName, type DisclosureContext } from "./DisclosureTypes";
|
|
3
|
+
|
|
4
|
+
interface DisclosureTriggerProps {
|
|
5
|
+
/** An ID for the root element */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Class name(s) for the root element */
|
|
8
|
+
class?: string,
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A header button for a Disclosure, which can be used to reveal or hide an associated DisclosureContent.
|
|
13
|
+
*/
|
|
14
|
+
export default function DisclosureTrigger($props: DisclosureTriggerProps) {
|
|
15
|
+
$props ??= $watch({});
|
|
16
|
+
$props.id ||= getId();
|
|
17
|
+
|
|
18
|
+
// Get stuff out of the DisclosureContext
|
|
19
|
+
const context = $context[DisclosureContextName] as DisclosureContext;
|
|
20
|
+
if (!context) {
|
|
21
|
+
throw new Error("DisclosureTrigger must be contained within a Disclosure");
|
|
22
|
+
}
|
|
23
|
+
let $state = context.state;
|
|
24
|
+
|
|
25
|
+
// Set the header ID so that it can be used with aria-labelledby in DisclosureContent
|
|
26
|
+
$state.headerId = $props.id;
|
|
27
|
+
|
|
28
|
+
@render {
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
{$props.id}
|
|
32
|
+
class={`torp-disclosure-trigger ${$props.class ?? ""}`.trim()}
|
|
33
|
+
disabled={$state.disabled || $state.parentDisabled}
|
|
34
|
+
aria-expanded={$state.expanded.toString()}
|
|
35
|
+
aria-disabled={$state.disabled}
|
|
36
|
+
aria-controls={$state.contentId}
|
|
37
|
+
data-state={$state.dataState}
|
|
38
|
+
data-disabled={$state.disabled}
|
|
39
|
+
onclick={() => $state.expanded = !$state.expanded}
|
|
40
|
+
>
|
|
41
|
+
<slot />
|
|
42
|
+
</button>
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DisclosureContextName = "Disclosure";
|
|
2
|
+
|
|
3
|
+
export interface DisclosureContext {
|
|
4
|
+
/** The reactive state for a Disclosure */
|
|
5
|
+
state: DisclosureState;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface DisclosureState {
|
|
9
|
+
headerId: string;
|
|
10
|
+
contentId: string;
|
|
11
|
+
expanded: boolean;
|
|
12
|
+
disabled: boolean;
|
|
13
|
+
dataState: "open" | "closed";
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import Disclosure from "./Disclosure.torp";
|
|
2
|
+
import DisclosureContent from "./DisclosureContent.torp";
|
|
3
|
+
import DisclosureHeader from "./DisclosureHeader.torp";
|
|
4
|
+
import DisclosureTrigger from "./DisclosureTrigger.torp";
|
|
5
|
+
|
|
6
|
+
export { Disclosure, DisclosureHeader, DisclosureTrigger, DisclosureContent };
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
interface DrawerProps {
|
|
3
|
+
/** An ID for the root element */
|
|
4
|
+
id?: string;
|
|
5
|
+
/** Class name(s) for the root element */
|
|
6
|
+
class?: string,
|
|
7
|
+
visible?: boolean,
|
|
8
|
+
position?: "left" | "right",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function Drawer($props: DrawerProps) {
|
|
12
|
+
$props ??= $watch({});
|
|
13
|
+
$props.visible ??= true;
|
|
4
14
|
$props.position ||= "left";
|
|
5
15
|
|
|
6
16
|
let offscreen: HTMLElement | undefined;
|
|
@@ -66,25 +76,16 @@ export default function Offscreen($props: any) {
|
|
|
66
76
|
}
|
|
67
77
|
}
|
|
68
78
|
|
|
69
|
-
function close() {
|
|
70
|
-
$props.visible = false;
|
|
71
|
-
if ($props.onclose) {
|
|
72
|
-
$props.onclose()
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
79
|
@render {
|
|
77
80
|
@if ($props.visible) {
|
|
78
|
-
<div
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<:slot />
|
|
87
|
-
</div>
|
|
81
|
+
<div
|
|
82
|
+
{$props.id}
|
|
83
|
+
class={`torp-offscreen ${$props.class ?? ""}`.trim()}
|
|
84
|
+
style="position: fixed;"
|
|
85
|
+
transition={transitionArgs()}
|
|
86
|
+
&ref={offscreen}
|
|
87
|
+
>
|
|
88
|
+
<slot />
|
|
88
89
|
</div>
|
|
89
90
|
}
|
|
90
91
|
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FormContextName,
|
|
3
|
+
FieldContextName,
|
|
4
|
+
type ValidationIssue,
|
|
5
|
+
type FormContext,
|
|
6
|
+
type FieldContext,
|
|
7
|
+
} from "./FormTypes";
|
|
8
|
+
import { StandardSchemaV1 } from "./StandardSchemaV1"
|
|
9
|
+
|
|
10
|
+
interface FieldProps {
|
|
11
|
+
/** An ID for the root element */
|
|
12
|
+
id?: string;
|
|
13
|
+
/** Class name(s) for the root element */
|
|
14
|
+
class?: string,
|
|
15
|
+
/** The name of the data that this field contains */
|
|
16
|
+
name: string,
|
|
17
|
+
/** The data value that this field is bound to */
|
|
18
|
+
value?: any,
|
|
19
|
+
/** The schema validator to use for this form */
|
|
20
|
+
schema?: StandardSchemaV1,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A field in a form which automatically links up a Label and/or an input
|
|
25
|
+
* component and/or a Message.
|
|
26
|
+
*/
|
|
27
|
+
export default function Field($props: FieldProps) {
|
|
28
|
+
$props ??= $watch({ name: "" });
|
|
29
|
+
|
|
30
|
+
let $state = $watch({
|
|
31
|
+
inputId: "-1",
|
|
32
|
+
value: $props.value,
|
|
33
|
+
issues: [] as ValidationIssue[],
|
|
34
|
+
get valid() {
|
|
35
|
+
return this.issues.find((i) => i.path === $props.name) === undefined;
|
|
36
|
+
},
|
|
37
|
+
get message() {
|
|
38
|
+
return this.issues.filter((i) => i.path === $props.name).map((i) => i.message).join("\n");
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Binding
|
|
43
|
+
$run(() => {
|
|
44
|
+
$props.value = $state.value;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Get stuff out of the FormContext, if applicable
|
|
48
|
+
const formContext = $context[FormContextName] as FormContext;
|
|
49
|
+
if (formContext) {
|
|
50
|
+
$run(() => {
|
|
51
|
+
$state.issues = formContext.state.issues;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Set the context to pass down to Labels, Inputs and Messages
|
|
56
|
+
let context: FieldContext = {
|
|
57
|
+
name: $props.name,
|
|
58
|
+
state: $state,
|
|
59
|
+
validate: handleValidate
|
|
60
|
+
};
|
|
61
|
+
$context[FieldContextName] = context;
|
|
62
|
+
|
|
63
|
+
async function validate() {
|
|
64
|
+
if ($props.schema) {
|
|
65
|
+
const validator = $props.schema["~standard"];
|
|
66
|
+
let result = validator.validate($props.value);
|
|
67
|
+
if (result instanceof Promise) {
|
|
68
|
+
result = await result;
|
|
69
|
+
}
|
|
70
|
+
let issues: ValidationIssue[] = [];
|
|
71
|
+
if (result.issues) {
|
|
72
|
+
for (let issue of result.issues) {
|
|
73
|
+
issues.push({ path: $props.name, message: issue.message });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
$state.issues = $state.issues.filter((e) => e.path !== $props.name).concat(issues);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function handleValidate() {
|
|
81
|
+
await validate();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@render {
|
|
85
|
+
<div
|
|
86
|
+
{$props.id}
|
|
87
|
+
class={`torp-field ${$props.class ?? ""}`.trim()}
|
|
88
|
+
data-valid={$state.valid ? "valid" : "invalid"}
|
|
89
|
+
>
|
|
90
|
+
<slot />
|
|
91
|
+
</div>
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { FormContextName, type ValidationIssue, type FormContext } from "./FormTypes";
|
|
2
|
+
import { StandardSchemaV1 } from "./StandardSchemaV1"
|
|
3
|
+
|
|
4
|
+
interface FormProps {
|
|
5
|
+
/** An ID for the root element */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** Class name(s) for the root element */
|
|
8
|
+
class?: string,
|
|
9
|
+
/** The data to display in the form */
|
|
10
|
+
data?: any,
|
|
11
|
+
/** Where to post the form's data **/
|
|
12
|
+
action?: string,
|
|
13
|
+
/** The schema validator to use for this form */
|
|
14
|
+
schema?: StandardSchemaV1,
|
|
15
|
+
onsubmit?: (e: SubmitEvent) => boolean | void | Promise<boolean | void>,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A form for submitting values.
|
|
20
|
+
*/
|
|
21
|
+
export default function Form($props: FormProps) {
|
|
22
|
+
$props ??= $watch({});
|
|
23
|
+
|
|
24
|
+
let $state = $watch({
|
|
25
|
+
data: $props.data ?? {},
|
|
26
|
+
issues: [] as ValidationIssue[],
|
|
27
|
+
get valid() {
|
|
28
|
+
return this.issues.length === 0;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
let submitted = false;
|
|
33
|
+
|
|
34
|
+
// TODO: Load context from build with a submit method that submits to a form action
|
|
35
|
+
|
|
36
|
+
// Set the context to pass down to Fields
|
|
37
|
+
let context: FormContext = {
|
|
38
|
+
schema: $props.schema,
|
|
39
|
+
state: $state,
|
|
40
|
+
validate: handleValidate
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
$context[FormContextName] = context;
|
|
44
|
+
|
|
45
|
+
async function validate() {
|
|
46
|
+
if ($props.schema) {
|
|
47
|
+
const validator = $props.schema["~standard"];
|
|
48
|
+
let result = validator.validate($props.data);
|
|
49
|
+
if (result instanceof Promise) {
|
|
50
|
+
result = await result;
|
|
51
|
+
}
|
|
52
|
+
let issues: ValidationIssue[] = [];
|
|
53
|
+
if (result.issues) {
|
|
54
|
+
for (let issue of result.issues) {
|
|
55
|
+
if (issue.path) {
|
|
56
|
+
// TODO: arrays with `[0]`
|
|
57
|
+
issues.push({ path: issue.path.join("."), message: issue.message });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
$state.issues = issues;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function handleSubmit(e: SubmitEvent) {
|
|
66
|
+
// Validate, and proceed with submission if there are no errors
|
|
67
|
+
await validate();
|
|
68
|
+
let proceed = $state.valid;
|
|
69
|
+
|
|
70
|
+
// Changing inputs from now on will cause revalidation
|
|
71
|
+
submitted = true;
|
|
72
|
+
|
|
73
|
+
// If validation failed, don't continue
|
|
74
|
+
if (!proceed) {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Dispatch the submit event for the user to handle
|
|
80
|
+
if ($props.onsubmit) {
|
|
81
|
+
let userSubmit = $props.onsubmit(e);
|
|
82
|
+
if (userSubmit instanceof Promise) {
|
|
83
|
+
userSubmit = await userSubmit;
|
|
84
|
+
}
|
|
85
|
+
proceed = userSubmit !== false && !e.defaultPrevented;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// If the user handled the submit, don't continue
|
|
89
|
+
if (!proceed) {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// If there's a @torpor/build context, call its submit event
|
|
95
|
+
let buildContext = $context["TorporBuildContext"];
|
|
96
|
+
if (buildContext?.onformsubmit) {
|
|
97
|
+
let buildSubmit = buildContext.onformsubmit(e);
|
|
98
|
+
if (buildSubmit instanceof Promise) {
|
|
99
|
+
buildSubmit = await buildSubmit;
|
|
100
|
+
}
|
|
101
|
+
proceed = buildSubmit !== false && !e.defaultPrevented;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// If @torpor/build handled the submit, don't continue
|
|
105
|
+
if (!proceed) {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Otherwise just let normal form submission go ahead...
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function handleValidate() {
|
|
114
|
+
if (submitted) {
|
|
115
|
+
await validate();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@render {
|
|
120
|
+
<form
|
|
121
|
+
{$props.id}
|
|
122
|
+
class={`torp-form ${$props.class ?? ""}`.trim()}
|
|
123
|
+
method="POST"
|
|
124
|
+
onsubmit={handleSubmit}
|
|
125
|
+
@// Set novalidate only if JS is enabled (to override HTML validation)
|
|
126
|
+
onmount={(e) => e.novalidate = true }
|
|
127
|
+
>
|
|
128
|
+
<slot />
|
|
129
|
+
</form>
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type StandardSchemaV1 } from "./StandardSchemaV1";
|
|
2
|
+
|
|
3
|
+
export const FormContextName: unique symbol = Symbol("Form");
|
|
4
|
+
export const FieldContextName: unique symbol = Symbol("Field");
|
|
5
|
+
|
|
6
|
+
export interface ValidationIssue {
|
|
7
|
+
path: string;
|
|
8
|
+
message: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FormContext {
|
|
12
|
+
schema?: StandardSchemaV1;
|
|
13
|
+
state: {
|
|
14
|
+
issues: ValidationIssue[];
|
|
15
|
+
};
|
|
16
|
+
validate: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FieldContext {
|
|
20
|
+
name: string;
|
|
21
|
+
schema?: StandardSchemaV1;
|
|
22
|
+
state: {
|
|
23
|
+
inputId: string;
|
|
24
|
+
value?: any;
|
|
25
|
+
issues: ValidationIssue[];
|
|
26
|
+
valid: boolean;
|
|
27
|
+
message: string;
|
|
28
|
+
};
|
|
29
|
+
validate: () => void;
|
|
30
|
+
}
|