@torpor/ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/Accordion/Accordion.torp +44 -25
- package/dist/Accordion/AccordionContent.torp +18 -12
- package/dist/Accordion/AccordionHeader.torp +15 -8
- package/dist/Accordion/AccordionItem.torp +34 -17
- package/dist/Accordion/AccordionTrigger.torp +17 -10
- package/dist/Accordion/AccordionTypes.ts +6 -3
- package/dist/Accordion/index.d.ts +100 -35
- package/dist/Breadcrumb/Breadcrumb.torp +18 -10
- package/dist/Breadcrumb/BreadcrumbItem.torp +14 -7
- package/dist/Breadcrumb/BreadcrumbSeparator.torp +10 -3
- package/dist/Breadcrumb/index.d.ts +50 -21
- package/dist/Calendar/Calendar.torp +21 -14
- package/dist/Calendar/CalendarDay.torp +12 -4
- package/dist/Calendar/index.d.ts +16 -18
- package/dist/Contextual/Contextual.torp +125 -0
- package/dist/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +21 -12
- package/dist/Contextual/ContextualTrigger.torp +66 -0
- package/dist/Contextual/ContextualTypes.ts +30 -0
- package/dist/Contextual/index.d.ts +90 -0
- package/dist/Contextual/index.js +14 -0
- package/dist/Contextual/index.js.map +1 -0
- package/dist/Dialog/Dialog.torp +49 -73
- package/dist/Dialog/DialogBody.torp +15 -9
- package/dist/Dialog/DialogButton.torp +27 -13
- package/dist/Dialog/DialogFooter.torp +11 -3
- package/dist/Dialog/DialogHeader.torp +15 -8
- package/dist/Dialog/DialogTypes.ts +3 -2
- package/dist/Dialog/index.d.ts +83 -35
- package/dist/Disclosure/Disclosure.torp +34 -25
- package/dist/Disclosure/DisclosureContent.torp +18 -12
- package/dist/Disclosure/DisclosureHeader.torp +16 -9
- package/dist/Disclosure/DisclosureTrigger.torp +15 -8
- package/dist/Disclosure/DisclosureTypes.ts +0 -1
- package/dist/Disclosure/index.d.ts +67 -28
- package/dist/Drawer/Drawer.torp +109 -68
- package/dist/Drawer/DrawerContent.torp +80 -0
- package/dist/Drawer/DrawerOverlay.torp +38 -0
- package/dist/Drawer/DrawerTrigger.torp +35 -0
- package/dist/Drawer/DrawerTypes.ts +24 -0
- package/dist/Drawer/index.d.ts +96 -8
- package/dist/Drawer/index.js +13 -1
- package/dist/Form/Field.torp +91 -0
- package/dist/Form/Form.torp +129 -0
- package/dist/Form/FormTypes.ts +30 -0
- package/dist/Form/Input.torp +97 -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 +131 -0
- package/dist/Form/index.js +22 -0
- package/dist/Form/index.js.map +1 -0
- package/dist/Menu/Menu.torp +25 -15
- package/dist/Menu/MenuButton.torp +30 -13
- package/dist/Menu/MenuCheck.torp +29 -14
- package/dist/Menu/MenuGroup.torp +14 -6
- package/dist/Menu/MenuIndicator.torp +14 -7
- package/dist/Menu/MenuPopout.torp +23 -15
- package/dist/Menu/MenuPopoutContent.torp +17 -10
- package/dist/Menu/MenuPopoutTrigger.torp +23 -16
- package/dist/Menu/MenuRadio.torp +27 -16
- package/dist/Menu/MenuRadioGroup.torp +34 -15
- package/dist/Menu/MenuSeparator.torp +11 -3
- package/dist/Menu/MenuTypes.ts +7 -5
- package/dist/Menu/index.d.ts +176 -77
- package/dist/MenuBar/MenuBar.torp +24 -16
- package/dist/MenuBar/MenuBarItem.torp +24 -16
- package/dist/MenuBar/MenuBarItemContent.torp +18 -11
- package/dist/MenuBar/MenuBarItemTrigger.torp +15 -9
- package/dist/MenuBar/index.d.ts +79 -28
- package/dist/Modal/Modal.torp +118 -0
- package/dist/Modal/ModalContent.torp +77 -0
- package/dist/Modal/ModalOverlay.torp +38 -0
- package/dist/Modal/ModalTrigger.torp +50 -0
- package/dist/Modal/ModalTypes.ts +22 -0
- package/dist/Modal/index.d.ts +108 -0
- package/dist/Modal/index.js +33 -0
- package/dist/Modal/index.js.map +1 -0
- package/dist/Modal/showModal.ts +19 -0
- package/dist/Modal/showPrompt.ts +23 -0
- package/dist/NavMenu/NavMenu.torp +18 -10
- package/dist/NavMenu/NavMenuButton.torp +15 -10
- package/dist/NavMenu/NavMenuElement.torp +19 -11
- package/dist/NavMenu/NavMenuGroup.torp +13 -6
- package/dist/NavMenu/NavMenuGroupHeader.torp +15 -8
- package/dist/NavMenu/NavMenuLink.torp +21 -16
- package/dist/NavMenu/NavMenuPopout.torp +34 -18
- package/dist/NavMenu/NavMenuPopoutButton.torp +23 -18
- package/dist/NavMenu/NavMenuPopoutContent.torp +23 -13
- package/dist/NavMenu/NavMenuSeparator.torp +10 -3
- package/dist/NavMenu/index.d.ts +153 -70
- package/dist/Notification/Notification.torp +35 -16
- package/dist/Notification/NotificationClose.torp +10 -3
- package/dist/Notification/NotificationContainer.torp +11 -3
- package/dist/Notification/NotificationContent.torp +11 -3
- package/dist/Notification/index.d.ts +46 -28
- package/dist/Popover/Popover.torp +48 -28
- package/dist/Popover/PopoverContent.torp +42 -8
- package/dist/Popover/PopoverTrigger.torp +32 -3
- package/dist/Popover/PopoverTypes.ts +1 -1
- package/dist/Popover/index.d.ts +48 -111
- package/dist/Popover/index.js +1 -163
- package/dist/Popover/index.js.map +1 -1
- package/dist/TabGroup/TabContent.torp +20 -11
- package/dist/TabGroup/TabGroup.torp +58 -40
- package/dist/TabGroup/TabGroupTypes.ts +10 -5
- package/dist/TabGroup/TabHeader.torp +26 -10
- package/dist/TabGroup/TabList.torp +14 -7
- package/dist/TabGroup/TabTrigger.torp +17 -10
- package/dist/TabGroup/index.d.ts +101 -35
- package/dist/icons/ArrowDown.torp +5 -3
- package/dist/icons/ArrowLeft.torp +5 -3
- package/dist/icons/ArrowRight.torp +5 -3
- package/dist/icons/ArrowUp.torp +5 -3
- package/dist/icons/Bars.torp +5 -3
- package/dist/icons/Check.torp +5 -3
- package/dist/icons/ChevronDown.torp +5 -3
- package/dist/icons/ChevronLeft.torp +5 -3
- package/dist/icons/ChevronRight.torp +5 -3
- package/dist/icons/ChevronUp.torp +5 -3
- package/dist/icons/Cross.torp +5 -3
- package/dist/icons/IconTypes.ts +6 -0
- package/dist/icons/Loading.torp +5 -3
- package/dist/icons/Minus.torp +5 -3
- package/dist/icons/Plus.torp +5 -3
- package/dist/icons/index.d.ts +271 -126
- package/dist/index.d.ts +17 -4
- package/dist/metafile-esm.json +1 -1
- package/dist/motion/fade.ts +15 -6
- package/dist/motion/grow.ts +23 -0
- package/dist/motion/index.d.ts +19 -2
- package/dist/motion/index.js +93 -3
- package/dist/motion/index.js.map +1 -1
- package/dist/motion/measure.ts +28 -0
- package/dist/motion/slide.ts +45 -0
- package/dist/mount/clickPopover.ts +51 -0
- package/dist/mount/contextPopover.ts +51 -0
- package/dist/mount/hoverPopover.ts +58 -0
- package/package.json +28 -12
- package/scripts/postbuild.ts +11 -1
- package/src/Accordion/Accordion.torp +44 -25
- package/src/Accordion/AccordionContent.torp +18 -12
- package/src/Accordion/AccordionHeader.torp +15 -8
- package/src/Accordion/AccordionItem.torp +34 -17
- package/src/Accordion/AccordionTrigger.torp +17 -10
- package/src/Accordion/AccordionTypes.ts +6 -3
- package/src/Breadcrumb/Breadcrumb.torp +18 -10
- package/src/Breadcrumb/BreadcrumbItem.torp +14 -7
- package/src/Breadcrumb/BreadcrumbSeparator.torp +10 -3
- package/src/Calendar/Calendar.torp +21 -14
- package/src/Calendar/CalendarDay.torp +12 -4
- package/src/Contextual/Contextual.torp +125 -0
- package/src/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +21 -12
- package/src/Contextual/ContextualTrigger.torp +66 -0
- package/src/Contextual/ContextualTypes.ts +30 -0
- package/src/Contextual/index.ts +5 -0
- package/src/Dialog/Dialog.torp +49 -73
- package/src/Dialog/DialogBody.torp +15 -9
- package/src/Dialog/DialogButton.torp +27 -13
- package/src/Dialog/DialogFooter.torp +11 -3
- package/src/Dialog/DialogHeader.torp +15 -8
- package/src/Dialog/DialogTypes.ts +3 -2
- package/src/Disclosure/Disclosure.torp +34 -25
- package/src/Disclosure/DisclosureContent.torp +18 -12
- package/src/Disclosure/DisclosureHeader.torp +16 -9
- package/src/Disclosure/DisclosureTrigger.torp +15 -8
- package/src/Disclosure/DisclosureTypes.ts +0 -1
- package/src/Drawer/Drawer.torp +109 -68
- package/src/Drawer/DrawerContent.torp +80 -0
- package/src/Drawer/DrawerOverlay.torp +38 -0
- package/src/Drawer/DrawerTrigger.torp +35 -0
- package/src/Drawer/DrawerTypes.ts +24 -0
- package/src/Drawer/index.ts +4 -1
- package/src/Form/Field.torp +91 -0
- package/src/Form/Form.torp +129 -0
- package/src/Form/FormTypes.ts +30 -0
- package/src/Form/Input.torp +97 -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 +25 -15
- package/src/Menu/MenuButton.torp +30 -13
- package/src/Menu/MenuCheck.torp +29 -14
- package/src/Menu/MenuGroup.torp +14 -6
- package/src/Menu/MenuIndicator.torp +14 -7
- package/src/Menu/MenuPopout.torp +23 -15
- package/src/Menu/MenuPopoutContent.torp +17 -10
- package/src/Menu/MenuPopoutTrigger.torp +23 -16
- package/src/Menu/MenuRadio.torp +27 -16
- package/src/Menu/MenuRadioGroup.torp +34 -15
- package/src/Menu/MenuSeparator.torp +11 -3
- package/src/Menu/MenuTypes.ts +7 -5
- package/src/MenuBar/MenuBar.torp +24 -16
- package/src/MenuBar/MenuBarItem.torp +24 -16
- package/src/MenuBar/MenuBarItemContent.torp +18 -11
- package/src/MenuBar/MenuBarItemTrigger.torp +15 -9
- package/src/Modal/Modal.torp +118 -0
- package/src/Modal/ModalContent.torp +77 -0
- package/src/Modal/ModalOverlay.torp +38 -0
- package/src/Modal/ModalTrigger.torp +50 -0
- package/src/Modal/ModalTypes.ts +22 -0
- package/src/Modal/index.ts +10 -0
- package/src/Modal/showModal.ts +19 -0
- package/src/Modal/showPrompt.ts +23 -0
- package/src/NavMenu/NavMenu.torp +18 -10
- package/src/NavMenu/NavMenuButton.torp +15 -10
- package/src/NavMenu/NavMenuElement.torp +19 -11
- package/src/NavMenu/NavMenuGroup.torp +13 -6
- package/src/NavMenu/NavMenuGroupHeader.torp +15 -8
- package/src/NavMenu/NavMenuLink.torp +21 -16
- package/src/NavMenu/NavMenuPopout.torp +34 -18
- package/src/NavMenu/NavMenuPopoutButton.torp +23 -18
- package/src/NavMenu/NavMenuPopoutContent.torp +23 -13
- package/src/NavMenu/NavMenuSeparator.torp +10 -3
- package/src/Notification/Notification.torp +35 -16
- package/src/Notification/NotificationClose.torp +10 -3
- package/src/Notification/NotificationContainer.torp +11 -3
- package/src/Notification/NotificationContent.torp +11 -3
- package/src/Popover/Popover.torp +48 -28
- package/src/Popover/PopoverContent.torp +42 -8
- package/src/Popover/PopoverTrigger.torp +32 -3
- package/src/Popover/PopoverTypes.ts +1 -1
- package/src/Popover/index.ts +1 -24
- package/src/Slider/Slider.torp +3 -3
- package/src/TabGroup/TabContent.torp +20 -11
- package/src/TabGroup/TabGroup.torp +58 -40
- package/src/TabGroup/TabGroupTypes.ts +10 -5
- package/src/TabGroup/TabHeader.torp +26 -10
- package/src/TabGroup/TabList.torp +14 -7
- package/src/TabGroup/TabTrigger.torp +17 -10
- package/src/icons/ArrowDown.torp +5 -3
- package/src/icons/ArrowLeft.torp +5 -3
- package/src/icons/ArrowRight.torp +5 -3
- package/src/icons/ArrowUp.torp +5 -3
- package/src/icons/Bars.torp +5 -3
- package/src/icons/Check.torp +5 -3
- package/src/icons/ChevronDown.torp +5 -3
- package/src/icons/ChevronLeft.torp +5 -3
- package/src/icons/ChevronRight.torp +5 -3
- package/src/icons/ChevronUp.torp +5 -3
- package/src/icons/Cross.torp +5 -3
- package/src/icons/IconTypes.ts +6 -0
- package/src/icons/Loading.torp +5 -3
- package/src/icons/Minus.torp +5 -3
- package/src/icons/Plus.torp +5 -3
- package/src/motion/fade.ts +15 -6
- package/src/motion/grow.ts +23 -0
- package/src/motion/index.ts +4 -1
- package/src/motion/measure.ts +28 -0
- package/src/motion/slide.ts +45 -0
- package/src/mount/clickPopover.ts +51 -0
- package/src/mount/contextPopover.ts +51 -0
- package/src/mount/hoverPopover.ts +58 -0
- package/test/Accordion/components/AccordionAccessibility.torp +1 -1
- package/test/Accordion/components/AccordionKeyboard.torp +1 -1
- package/test/Accordion/components/AccordionList.torp +1 -1
- package/test/Accordion/components/AccordionMultiple.torp +2 -2
- package/test/Accordion/components/AccordionSingle.torp +2 -2
- package/test/Dialog/accessibility-modal.test.ts +2 -2
- package/test/Dialog/components/DialogAccessibility.torp +8 -14
- package/test/Dialog/components/DialogFunction.torp +20 -4
- package/test/Dialog/components/DialogModal.torp +30 -0
- package/test/Dialog/components/DialogVariable.torp +7 -7
- package/test/Disclosure/accessibility.test.ts +3 -2
- package/test/Disclosure/components/DisclosureTest.torp +1 -1
- package/test/Disclosure/toggle.test.ts +3 -2
- 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 +3 -2
- package/test/Menu/basic.test.ts +11 -10
- package/test/Menu/components/MenuAccessibility.torp +5 -5
- package/test/Menu/components/MenuBasic.torp +5 -5
- package/test/MenuBar/accessibility.test.ts +3 -2
- package/test/MenuBar/basic.test.ts +3 -2
- package/test/NavMenu/basic.test.ts +1 -1
- package/test/NavMenu/components/{NavMenu.torp → NavMenuBasic.torp} +1 -1
- package/test/Notification/components/NotificationFunction.torp +0 -3
- package/test/Notification/components/NotificationVariable.torp +1 -1
- package/test/Popover/components/PopoverFunction.torp +37 -0
- package/test/Popover/components/PopoverTrigger.torp +36 -0
- package/test/Popover/components/{PromptVariable.torp → PopoverVariable.torp} +5 -3
- package/test/Popover/function.test.ts +2 -7
- package/test/Popover/trigger.test.ts +27 -0
- package/test/Popover/variable.test.ts +2 -2
- package/test/TabGroup/components/TabGroupAccessibility.torp +1 -1
- package/test/TabGroup/components/TabGroupKeyboard.torp +1 -1
- package/test/TabGroup/components/TabGroupList.torp +1 -1
- package/test/TabGroup/components/TabGroupTrigger.torp +1 -1
- package/tsup.config.ts +3 -1
- package/dist/Popover/PopoverContentAnchored.torp +0 -106
- package/dist/Popover/PopoverOverlay.torp +0 -30
- package/dist/Popover/PopoverTriggerContextual.torp +0 -37
- package/dist/Popover/PopoverTriggerHover.torp +0 -38
- package/dist/Popover/mountClickPopover.ts +0 -50
- package/dist/Popover/mountContextPopover.ts +0 -50
- package/dist/Popover/mountHoverPopover.ts +0 -57
- package/dist/Popover/showPopoverPrompt.ts +0 -23
- package/src/Popover/PopoverContentAnchored.torp +0 -106
- package/src/Popover/PopoverOverlay.torp +0 -30
- package/src/Popover/PopoverTriggerContextual.torp +0 -37
- package/src/Popover/PopoverTriggerHover.torp +0 -38
- package/src/Popover/mountClickPopover.ts +0 -50
- package/src/Popover/mountContextPopover.ts +0 -50
- package/src/Popover/mountHoverPopover.ts +0 -57
- package/src/Popover/showPopoverPrompt.ts +0 -23
- package/test/Dialog/components/CustomDialog.torp +0 -20
- package/test/Popover/components/PromptFunction.torp +0 -19
package/src/icons/Minus.torp
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { type IconProps } from "./IconTypes";
|
|
2
|
+
|
|
3
|
+
export default function Minus($props: IconProps | undefined) {
|
|
2
4
|
@render {
|
|
3
5
|
<svg
|
|
4
|
-
{$props
|
|
5
|
-
class={`torp-icon ${$props
|
|
6
|
+
{$props?.id}
|
|
7
|
+
class={`torp-icon ${$props?.class ?? ""}`.trim()}
|
|
6
8
|
viewBox="0 0 100 100"
|
|
7
9
|
stroke-linejoin="round"
|
|
8
10
|
stroke-width="12"
|
package/src/icons/Plus.torp
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { type IconProps } from "./IconTypes";
|
|
2
|
+
|
|
3
|
+
export default function Plus($props: IconProps | undefined) {
|
|
2
4
|
@render {
|
|
3
5
|
<svg
|
|
4
|
-
{$props
|
|
5
|
-
class={`torp-icon ${$props
|
|
6
|
+
{$props?.id}
|
|
7
|
+
class={`torp-icon ${$props?.class ?? ""}`.trim()}
|
|
6
8
|
viewBox="0 0 100 100"
|
|
7
9
|
stroke-linejoin="round"
|
|
8
10
|
stroke-width="12"
|
package/src/motion/fade.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
opacity: number;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
const animationFrames: AnimationFrame[] = [{ opacity: 0 }, { opacity: 1 }];
|
|
1
|
+
import { type Animation } from "@torpor/view";
|
|
6
2
|
|
|
7
|
-
export default
|
|
3
|
+
export default function fade(
|
|
4
|
+
_el: HTMLElement,
|
|
5
|
+
options?: number | KeyframeAnimationOptions,
|
|
6
|
+
): Animation {
|
|
7
|
+
const keyframes = [
|
|
8
|
+
{
|
|
9
|
+
opacity: 0,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
opacity: 1,
|
|
13
|
+
},
|
|
14
|
+
];
|
|
15
|
+
return { keyframes, options };
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Animation } from "@torpor/view";
|
|
2
|
+
import measure from "./measure";
|
|
3
|
+
|
|
4
|
+
export default function grow(
|
|
5
|
+
el: HTMLElement,
|
|
6
|
+
options?: number | KeyframeAnimationOptions,
|
|
7
|
+
): Animation {
|
|
8
|
+
const height = measure(el, (el) => el.clientHeight);
|
|
9
|
+
const keyframes = [
|
|
10
|
+
{
|
|
11
|
+
height: "0px",
|
|
12
|
+
overflow: "hidden",
|
|
13
|
+
paddingTop: "0px",
|
|
14
|
+
paddingBottom: "0px",
|
|
15
|
+
marginTop: "0px",
|
|
16
|
+
marginBottom: "0px",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
height: height + "px",
|
|
20
|
+
},
|
|
21
|
+
];
|
|
22
|
+
return { keyframes, options };
|
|
23
|
+
}
|
package/src/motion/index.ts
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Measures an element before it is added to the DOM
|
|
3
|
+
* @param el The element to measure
|
|
4
|
+
* @param fn The function to use to get the desired measurement (e.g. el.offsetHeight)
|
|
5
|
+
*/
|
|
6
|
+
export default function measure(el: HTMLElement, fn: (_: HTMLElement) => number): number {
|
|
7
|
+
// From https://stackoverflow.com/a/46707458
|
|
8
|
+
let oldVisibility = el.style.visibility;
|
|
9
|
+
let oldPosition = el.style.position;
|
|
10
|
+
|
|
11
|
+
let oldParent = el.parentNode;
|
|
12
|
+
let oldBefore = el.nextSibling;
|
|
13
|
+
|
|
14
|
+
el.style.visibility = "hidden";
|
|
15
|
+
el.style.position = "absolute";
|
|
16
|
+
|
|
17
|
+
document.body.appendChild(el);
|
|
18
|
+
let result = fn(el);
|
|
19
|
+
el.parentNode!.removeChild(el);
|
|
20
|
+
|
|
21
|
+
if (oldParent !== null) {
|
|
22
|
+
oldParent.insertBefore(el, oldBefore);
|
|
23
|
+
el.style.visibility = oldVisibility;
|
|
24
|
+
el.style.position = oldPosition;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type Animation } from "@torpor/view";
|
|
2
|
+
import measure from "./measure";
|
|
3
|
+
|
|
4
|
+
interface Options extends KeyframeAnimationOptions {
|
|
5
|
+
side: "left" | "right" | "top" | "bottom";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function slide(el: HTMLElement, options?: Options): Animation {
|
|
9
|
+
let position = options?.side ?? "left";
|
|
10
|
+
switch (position) {
|
|
11
|
+
case "left": {
|
|
12
|
+
el.style.left = "0px";
|
|
13
|
+
const width = measure(el, (el) => el.offsetWidth);
|
|
14
|
+
const keyframes = [
|
|
15
|
+
{ transform: `translateX(-${width}px)` },
|
|
16
|
+
{ transform: "translateX(0px)" },
|
|
17
|
+
];
|
|
18
|
+
return { keyframes, options };
|
|
19
|
+
}
|
|
20
|
+
case "top": {
|
|
21
|
+
el.style.top = "0px";
|
|
22
|
+
const height = measure(el, (el) => el.offsetHeight);
|
|
23
|
+
const keyframes = [
|
|
24
|
+
{ transform: `translateY(-${height}px)` },
|
|
25
|
+
{ transform: "translateY(0px)" },
|
|
26
|
+
];
|
|
27
|
+
return { keyframes, options };
|
|
28
|
+
}
|
|
29
|
+
case "right": {
|
|
30
|
+
el.style.right = "0px";
|
|
31
|
+
const width = measure(el, (el) => el.offsetWidth);
|
|
32
|
+
const keyframes = [{ transform: `translateX(${width}px)` }, { transform: "translateX(0px)" }];
|
|
33
|
+
return { keyframes, options };
|
|
34
|
+
}
|
|
35
|
+
case "bottom": {
|
|
36
|
+
el.style.bottom = "0px";
|
|
37
|
+
const height = measure(el, (el) => el.offsetHeight);
|
|
38
|
+
const keyframes = [
|
|
39
|
+
{ transform: `translateY(${height}px)` },
|
|
40
|
+
{ transform: "translateY(0px)" },
|
|
41
|
+
];
|
|
42
|
+
return { keyframes, options };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//import type { Component } from "@torpor/view";
|
|
2
|
+
//import showPopover from "../Modal/showModal";
|
|
3
|
+
//
|
|
4
|
+
//interface ClickPopoverOptions {
|
|
5
|
+
// popover: Component;
|
|
6
|
+
// props?: Record<PropertyKey, any>;
|
|
7
|
+
//}
|
|
8
|
+
//
|
|
9
|
+
///**
|
|
10
|
+
// * A mount directive for showing a popover when an element is clicked.
|
|
11
|
+
// * @param node The element to show the popover for
|
|
12
|
+
// * @param options Options for showing the popover, consisting of the popover component and any props
|
|
13
|
+
// */
|
|
14
|
+
//export default function clickPopover(node: HTMLElement, options: ClickPopoverOptions) {
|
|
15
|
+
// const { popover, props } = options;
|
|
16
|
+
//
|
|
17
|
+
// // Add a click event handler to the node
|
|
18
|
+
// node.addEventListener("click", handleClick);
|
|
19
|
+
//
|
|
20
|
+
// function handleClick(e: MouseEvent) {
|
|
21
|
+
// e.preventDefault();
|
|
22
|
+
// show();
|
|
23
|
+
// }
|
|
24
|
+
//
|
|
25
|
+
// let div: HTMLDivElement;
|
|
26
|
+
//
|
|
27
|
+
// function show() {
|
|
28
|
+
// // Show the popover in a div
|
|
29
|
+
// if (div) {
|
|
30
|
+
// document.body.removeChild(div);
|
|
31
|
+
// }
|
|
32
|
+
// div = document.createElement("div");
|
|
33
|
+
// document.body.appendChild(div);
|
|
34
|
+
//
|
|
35
|
+
// showPopover(popover, node, props, div);
|
|
36
|
+
// }
|
|
37
|
+
//
|
|
38
|
+
// return {
|
|
39
|
+
// destroy(): void {
|
|
40
|
+
// // Remove the event listener from the node on destroy
|
|
41
|
+
// node.removeEventListener("click", handleClick);
|
|
42
|
+
//
|
|
43
|
+
// // Remove the div we added
|
|
44
|
+
// // TODO: Should we do this in more places?
|
|
45
|
+
// if (div) {
|
|
46
|
+
// document.body.removeChild(div);
|
|
47
|
+
// }
|
|
48
|
+
// },
|
|
49
|
+
// };
|
|
50
|
+
//}
|
|
51
|
+
//
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//import type { Component } from "@torpor/view";
|
|
2
|
+
//import showPopover from "../Modal/showModal";
|
|
3
|
+
//
|
|
4
|
+
//interface ContextPopoverOptions {
|
|
5
|
+
// popover: Component;
|
|
6
|
+
// props?: Record<PropertyKey, any>;
|
|
7
|
+
//}
|
|
8
|
+
//
|
|
9
|
+
///**
|
|
10
|
+
// * A mount directive for showing a popover when the user opens an element's context menu.
|
|
11
|
+
// * @param node The element to show the popover for
|
|
12
|
+
// * @param options Options for showing the popover, consisting of the popover component and any props
|
|
13
|
+
// */
|
|
14
|
+
//export default function contextPopover(node: HTMLElement, options: ContextPopoverOptions) {
|
|
15
|
+
// const { popover, props } = options;
|
|
16
|
+
//
|
|
17
|
+
// // Add a contextmenu event handler to the node
|
|
18
|
+
// node.addEventListener("contextmenu", handleClick);
|
|
19
|
+
//
|
|
20
|
+
// function handleClick(e: MouseEvent) {
|
|
21
|
+
// e.preventDefault();
|
|
22
|
+
// show();
|
|
23
|
+
// }
|
|
24
|
+
//
|
|
25
|
+
// let div: HTMLDivElement;
|
|
26
|
+
//
|
|
27
|
+
// function show() {
|
|
28
|
+
// // Show the popover in a div
|
|
29
|
+
// if (div) {
|
|
30
|
+
// document.body.removeChild(div);
|
|
31
|
+
// }
|
|
32
|
+
// div = document.createElement("div");
|
|
33
|
+
// document.body.appendChild(div);
|
|
34
|
+
//
|
|
35
|
+
// showPopover(popover, node, props, div);
|
|
36
|
+
// }
|
|
37
|
+
//
|
|
38
|
+
// return {
|
|
39
|
+
// destroy(): void {
|
|
40
|
+
// // Remove the event listener from the node on destroy
|
|
41
|
+
// node.removeEventListener("contextmenu", handleClick);
|
|
42
|
+
//
|
|
43
|
+
// // Remove the div we added
|
|
44
|
+
// // TODO: Should we do this in more places?
|
|
45
|
+
// if (div) {
|
|
46
|
+
// document.body.removeChild(div);
|
|
47
|
+
// }
|
|
48
|
+
// },
|
|
49
|
+
// };
|
|
50
|
+
//}
|
|
51
|
+
//
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//import type { Component } from "@torpor/view";
|
|
2
|
+
//import showPopover from "../Modal/showModal";
|
|
3
|
+
//import hoverTrigger from "./hoverTrigger";
|
|
4
|
+
//
|
|
5
|
+
//interface HoverPopoverOptions {
|
|
6
|
+
// popover: Component;
|
|
7
|
+
// props?: Record<PropertyKey, any>;
|
|
8
|
+
// hoverDelay?: number;
|
|
9
|
+
// touchDelay?: number;
|
|
10
|
+
//}
|
|
11
|
+
//
|
|
12
|
+
///**
|
|
13
|
+
// * A mount directive for showing a popover when an element is hovered.
|
|
14
|
+
// * @param node The element to show the popover for
|
|
15
|
+
// * @param options Options for showing the popover, consisting of the popover component, any props and delays for hover and touch
|
|
16
|
+
// */
|
|
17
|
+
//export default function hoverPopover(node: HTMLElement, options: HoverPopoverOptions): () => void {
|
|
18
|
+
// const { popover, props, hoverDelay, touchDelay } = options;
|
|
19
|
+
//
|
|
20
|
+
// let div: HTMLDivElement | undefined;
|
|
21
|
+
//
|
|
22
|
+
// function onHover(node: HTMLElement, e: MouseEvent | TouchEvent) {
|
|
23
|
+
// // Show the popover in a div
|
|
24
|
+
// if (div) {
|
|
25
|
+
// document.body.removeChild(div);
|
|
26
|
+
// }
|
|
27
|
+
// div = document.createElement("div");
|
|
28
|
+
// document.body.appendChild(div);
|
|
29
|
+
//
|
|
30
|
+
// // Get the position relative to the element, so we can reposition on scroll
|
|
31
|
+
// const rect = node.getBoundingClientRect();
|
|
32
|
+
// let position: { x: number; y: number };
|
|
33
|
+
// if (e.type.startsWith("mouse")) {
|
|
34
|
+
// const me = e as MouseEvent;
|
|
35
|
+
// position = { x: me.clientX - rect.left, y: me.clientY - rect.top };
|
|
36
|
+
// } else {
|
|
37
|
+
// const te = e as TouchEvent;
|
|
38
|
+
// position = {
|
|
39
|
+
// x: te.touches[0].clientX - rect.left,
|
|
40
|
+
// y: te.touches[0].clientY - rect.top,
|
|
41
|
+
// };
|
|
42
|
+
// }
|
|
43
|
+
// const allProps = Object.assign({}, props, { anchor: node, position });
|
|
44
|
+
//
|
|
45
|
+
// showPopover(popover, node, allProps, div);
|
|
46
|
+
// }
|
|
47
|
+
//
|
|
48
|
+
// function onExit() {
|
|
49
|
+
// // Remove the div
|
|
50
|
+
// if (div) {
|
|
51
|
+
// document.body.removeChild(div);
|
|
52
|
+
// div = undefined;
|
|
53
|
+
// }
|
|
54
|
+
// }
|
|
55
|
+
//
|
|
56
|
+
// return hoverTrigger(node, { onHover, onExit, hoverDelay, touchDelay });
|
|
57
|
+
//}
|
|
58
|
+
//
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
AccordionContent,
|
|
7
7
|
} from "../../../src/Accordion/index";
|
|
8
8
|
|
|
9
|
-
export default function AccordionAccessibility() {
|
|
9
|
+
export default function AccordionAccessibility($props: any) {
|
|
10
10
|
@render {
|
|
11
11
|
<Accordion value={$props.value} type="multiple">
|
|
12
12
|
<AccordionItem>
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
AccordionContent,
|
|
7
7
|
} from "../../../src/Accordion/index";
|
|
8
8
|
|
|
9
|
-
export default function AccordionMultiple() {
|
|
9
|
+
export default function AccordionMultiple($props: any) {
|
|
10
10
|
@render {
|
|
11
|
-
<Accordion value={$props
|
|
11
|
+
<Accordion value={$props?.value} type="multiple">
|
|
12
12
|
<AccordionItem>
|
|
13
13
|
<AccordionHeader as="h4">
|
|
14
14
|
<AccordionTrigger>Header 1</AccordionTrigger>
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
AccordionContent,
|
|
7
7
|
} from "../../../src/Accordion/index";
|
|
8
8
|
|
|
9
|
-
export default function AccordionSingle() {
|
|
9
|
+
export default function AccordionSingle($props: any) {
|
|
10
10
|
@render {
|
|
11
|
-
<Accordion value={$props
|
|
11
|
+
<Accordion value={$props?.value}>
|
|
12
12
|
<AccordionItem>
|
|
13
13
|
<AccordionHeader as="h4">
|
|
14
14
|
<AccordionTrigger>Header 1</AccordionTrigger>
|
|
@@ -2,13 +2,13 @@ import { queryByText } from "@testing-library/dom";
|
|
|
2
2
|
import "@testing-library/jest-dom/vitest";
|
|
3
3
|
import { mount } from "@torpor/view";
|
|
4
4
|
import { assert, describe, expect, it } from "vitest";
|
|
5
|
-
import
|
|
5
|
+
import DialogModal from "./components/DialogModal.torp";
|
|
6
6
|
|
|
7
7
|
describe("Dialog", () => {
|
|
8
8
|
it("Accessibility -- modal", async () => {
|
|
9
9
|
const container = document.createElement("div");
|
|
10
10
|
document.body.appendChild(container);
|
|
11
|
-
mount(container,
|
|
11
|
+
mount(container, DialogModal, { modal: true, ariaAnnounce: false });
|
|
12
12
|
|
|
13
13
|
// Tests from https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/
|
|
14
14
|
// This is for a Dialog in a Popover with its modal property set to true
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Popover, PopoverContent } from "../../../src/Popover/index";
|
|
2
1
|
import {
|
|
3
2
|
Dialog,
|
|
4
3
|
DialogHeader,
|
|
@@ -8,24 +7,19 @@ import {
|
|
|
8
7
|
} from "../../../src/Dialog/index";
|
|
9
8
|
|
|
10
9
|
export default function DialogAccessibility($props: any) {
|
|
11
|
-
$props.modal ??= false;
|
|
12
10
|
$props.alert ??= false;
|
|
13
11
|
$props.ariaAnnounce ??= true;
|
|
14
12
|
|
|
15
13
|
let color = "";
|
|
16
14
|
|
|
17
15
|
@render {
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
</DialogFooter>
|
|
27
|
-
</Dialog>
|
|
28
|
-
</PopoverContent>
|
|
29
|
-
</Popover>
|
|
16
|
+
<Dialog alert={$props.alert}>
|
|
17
|
+
<DialogHeader>Color preference</DialogHeader>
|
|
18
|
+
<DialogBody ariaAnnounce={$props.ariaAnnounce}>Which color do you prefer?</DialogBody>
|
|
19
|
+
<DialogFooter>
|
|
20
|
+
<DialogButton value="blue" onclick={() => (color = "blue")}>Blue</DialogButton>
|
|
21
|
+
<DialogButton value="red" onclick={() => (color = "red")}>Red</DialogButton>
|
|
22
|
+
</DialogFooter>
|
|
23
|
+
</Dialog>
|
|
30
24
|
}
|
|
31
25
|
}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { Modal, ModalContent, showPrompt } from "../../../src/Modal/index";
|
|
2
|
+
import { Dialog, DialogBody, DialogFooter, DialogButton } from "../../../src/Dialog/index";
|
|
3
3
|
|
|
4
4
|
export default function DialogFunction($props: any) {
|
|
5
5
|
let $state = $watch({ color: "" });
|
|
6
6
|
|
|
7
7
|
async function show() {
|
|
8
|
-
|
|
9
|
-
$state.color = await showPopoverPrompt(CustomDialog, null, $parent);
|
|
8
|
+
$state.color = await showPrompt(CustomDialog, null, $parent);
|
|
10
9
|
}
|
|
11
10
|
|
|
12
11
|
@render {
|
|
@@ -18,3 +17,20 @@ export default function DialogFunction($props: any) {
|
|
|
18
17
|
}
|
|
19
18
|
}
|
|
20
19
|
|
|
20
|
+
function CustomDialog($props: any) {
|
|
21
|
+
@render {
|
|
22
|
+
<Modal visible callback={$props.callback}>
|
|
23
|
+
<ModalContent>
|
|
24
|
+
<Dialog>
|
|
25
|
+
<DialogBody>
|
|
26
|
+
<p>Which color do you prefer?</p>
|
|
27
|
+
</DialogBody>
|
|
28
|
+
<DialogFooter>
|
|
29
|
+
<DialogButton value="blue">Blue</DialogButton>
|
|
30
|
+
<DialogButton value="red">Red</DialogButton>
|
|
31
|
+
</DialogFooter>
|
|
32
|
+
</Dialog>
|
|
33
|
+
</ModalContent>
|
|
34
|
+
</Modal>
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Modal, ModalContent } from "../../../src/Modal/index";
|
|
2
|
+
import {
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogHeader,
|
|
5
|
+
DialogBody,
|
|
6
|
+
DialogFooter,
|
|
7
|
+
DialogButton
|
|
8
|
+
} from "../../../src/Dialog/index";
|
|
9
|
+
|
|
10
|
+
export default function DialogModal($props: any) {
|
|
11
|
+
$props.alert ??= false;
|
|
12
|
+
$props.ariaAnnounce ??= true;
|
|
13
|
+
|
|
14
|
+
let color = "";
|
|
15
|
+
|
|
16
|
+
@render {
|
|
17
|
+
<Modal visible>
|
|
18
|
+
<ModalContent>
|
|
19
|
+
<Dialog alert={$props.alert}>
|
|
20
|
+
<DialogHeader>Color preference</DialogHeader>
|
|
21
|
+
<DialogBody ariaAnnounce={$props.ariaAnnounce}>Which color do you prefer?</DialogBody>
|
|
22
|
+
<DialogFooter>
|
|
23
|
+
<DialogButton value="blue" onclick={() => (color = "blue")}>Blue</DialogButton>
|
|
24
|
+
<DialogButton value="red" onclick={() => (color = "red")}>Red</DialogButton>
|
|
25
|
+
</DialogFooter>
|
|
26
|
+
</Dialog>
|
|
27
|
+
</ModalContent>
|
|
28
|
+
</Modal>
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Modal, ModalContent } from "../../../src/Modal/index";
|
|
2
2
|
import { Dialog, DialogBody, DialogFooter, DialogButton } from "../../../src/Dialog/index";
|
|
3
3
|
|
|
4
4
|
export default function DialogVariable($props: any) {
|
|
5
5
|
let $state = $watch({
|
|
6
6
|
color: "",
|
|
7
|
-
|
|
7
|
+
showModal: false
|
|
8
8
|
});
|
|
9
9
|
|
|
10
10
|
@render {
|
|
11
|
-
<button type="button" onclick={(e) => ($state.
|
|
11
|
+
<button type="button" onclick={(e) => ($state.showModal = !$state.showModal)}>
|
|
12
12
|
Show the modal
|
|
13
13
|
</button>
|
|
14
14
|
|
|
@@ -16,8 +16,8 @@ export default function DialogVariable($props: any) {
|
|
|
16
16
|
<p>Your favorite color is {$state.color}?!</p>
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
<
|
|
20
|
-
<
|
|
19
|
+
<Modal &visible={$state.showModal}>
|
|
20
|
+
<ModalContent>
|
|
21
21
|
<Dialog>
|
|
22
22
|
<DialogBody>
|
|
23
23
|
<p>Which color do you prefer?</p>
|
|
@@ -27,7 +27,7 @@ export default function DialogVariable($props: any) {
|
|
|
27
27
|
<DialogButton value="red" onclick={() => ($state.color = "red")}>Red</DialogButton>
|
|
28
28
|
</DialogFooter>
|
|
29
29
|
</Dialog>
|
|
30
|
-
</
|
|
31
|
-
</
|
|
30
|
+
</ModalContent>
|
|
31
|
+
</Modal>
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
2
|
import "@testing-library/jest-dom/vitest";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
3
4
|
import { mount } from "@torpor/view";
|
|
4
5
|
import { describe, expect, it } from "vitest";
|
|
5
6
|
import DisclosureTest from "./components/DisclosureTest.torp";
|
|
@@ -19,7 +20,7 @@ describe("Disclosure", () => {
|
|
|
19
20
|
expect(queryByText(container, "Disclosure header")).toHaveAttribute("aria-expanded", "false");
|
|
20
21
|
|
|
21
22
|
// When the content area is visible, it is set to true
|
|
22
|
-
|
|
23
|
+
await userEvent.click(getByText(container, "Disclosure header"));
|
|
23
24
|
expect(queryByText(container, "Disclosure header")).toHaveAttribute("aria-expanded", "true");
|
|
24
25
|
|
|
25
26
|
// Optionally, the element with role button has a value specified for aria-controls that refers
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
export default function DisclosureAccessibility($props: { expanded: boolean }) {
|
|
9
9
|
@render {
|
|
10
|
-
<Disclosure {$props
|
|
10
|
+
<Disclosure {$props?.expanded}>
|
|
11
11
|
<DisclosureHeader as="h4">
|
|
12
12
|
<DisclosureTrigger>Disclosure header</DisclosureTrigger>
|
|
13
13
|
</DisclosureHeader>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getByText, queryByText } from "@testing-library/dom";
|
|
2
2
|
import "@testing-library/jest-dom/vitest";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
3
4
|
import { mount } from "@torpor/view";
|
|
4
5
|
import { describe, expect, it } from "vitest";
|
|
5
6
|
import DisclosureTest from "./components/DisclosureTest.torp";
|
|
@@ -13,7 +14,7 @@ describe("Disclosure", () => {
|
|
|
13
14
|
expect(queryByText(container, "Disclosure content")).not.toBeInTheDocument();
|
|
14
15
|
|
|
15
16
|
// Clicking the header should reveal the body
|
|
16
|
-
|
|
17
|
+
await userEvent.click(getByText(container, "Disclosure header"));
|
|
17
18
|
expect(queryByText(container, "Disclosure content")).toBeInTheDocument();
|
|
18
19
|
});
|
|
19
20
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Field,
|
|
3
|
+
Label,
|
|
4
|
+
Input,
|
|
5
|
+
Message,
|
|
6
|
+
} from "../../../src/Form/index";
|
|
7
|
+
import * as z from "zod";
|
|
8
|
+
|
|
9
|
+
export default function FormTest($props: { value: string }) {
|
|
10
|
+
const schema = z.string().trim().min(1, { message: 'Name is required!' });
|
|
11
|
+
|
|
12
|
+
let $state = $watch({
|
|
13
|
+
data: {
|
|
14
|
+
name: "",
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
@render {
|
|
19
|
+
<Field name="name" &value={$state.data.name} {schema}>
|
|
20
|
+
<Label>Name:</Label>
|
|
21
|
+
<Input id="name-id" placeholder="Name..." />
|
|
22
|
+
<Message />
|
|
23
|
+
</Field>
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Form,
|
|
3
|
+
Field,
|
|
4
|
+
Label,
|
|
5
|
+
Input,
|
|
6
|
+
Message,
|
|
7
|
+
} from "../../../src/Form/index";
|
|
8
|
+
import * as z from "zod";
|
|
9
|
+
|
|
10
|
+
export default function FormTest($props: { value: string }) {
|
|
11
|
+
const schema = z.object({
|
|
12
|
+
name: z.string().trim().min(1, { message: 'Name is required!' }),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
let $state = $watch({
|
|
16
|
+
data: {
|
|
17
|
+
name: "",
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
@render {
|
|
22
|
+
<Form {$state.data} {schema}>
|
|
23
|
+
<Field name="name" &value={$state.data.name}>
|
|
24
|
+
<Label>Name:</Label>
|
|
25
|
+
<Input id="name-id" placeholder="Name..." />
|
|
26
|
+
<Message />
|
|
27
|
+
</Field>
|
|
28
|
+
<button>Submit</button>
|
|
29
|
+
</Form>
|
|
30
|
+
}
|
|
31
|
+
}
|