@rpcbase/ui 0.17.0 → 0.19.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/package.json CHANGED
@@ -1,54 +1,19 @@
1
1
  {
2
2
  "name": "@rpcbase/ui",
3
- "version": "0.17.0",
4
- "license": "SSPL-1.0",
5
- "publishConfig": {
6
- "registry": "https://registry.npmjs.org/"
7
- },
8
- "files": [
9
- "**/*.js",
10
- "**/*.css",
11
- "**/*.scss",
12
- "!**/*.test.js",
13
- "!.wireit/**"
14
- ],
3
+ "version": "0.19.0",
4
+ "type": "module",
5
+ "main": "./src/index.ts",
15
6
  "scripts": {
16
- "test": "echo \"Error: no test specified\" && exit 0"
7
+ "release": "wireit"
17
8
  },
18
9
  "wireit": {
19
- "install": {
20
- "command": "NODE_ENV=development yarn install --mutex network --frozen-lockfile",
21
- "files": [
22
- "yarn.lock"
23
- ],
24
- "output": [
25
- "node_modules/"
26
- ],
27
- "allowUsuallyExcludedPaths": true
28
- },
29
- "apply-version": {
30
- "command": "node ../../scripts/prflow/apply-prerelease-versions.js $BRANCH_NAME",
31
- "files": [
32
- "package.json"
33
- ],
34
- "output": [],
35
- "env": {
36
- "BRANCH_NAME": {
37
- "external": true
38
- }
39
- }
40
- },
41
10
  "release": {
42
- "command": "npm publish --tag $NPM_RELEASE_CHANNEL | tee publish-output.txt",
43
- "dependencies": [
44
- "apply-version"
45
- ],
11
+ "command": "../../scripts/publish.js",
12
+ "dependencies": [],
46
13
  "files": [
47
14
  "package.json"
48
15
  ],
49
- "output": [
50
- "publish-output.txt"
51
- ],
16
+ "output": [],
52
17
  "env": {
53
18
  "NPM_RELEASE_CHANNEL": {
54
19
  "external": true
@@ -56,8 +21,6 @@
56
21
  }
57
22
  }
58
23
  },
59
- "dependencies": {
60
- "@rpcbase/lottie": "3.5.3",
61
- "@ui-kitten/components": "5.3.1"
62
- }
24
+ "dependencies": {},
25
+ "devDependencies": {}
63
26
  }
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+
3
+ interface CheckboxProps
4
+ extends Partial<Omit<React.InputHTMLAttributes<HTMLInputElement>, "type">> {
5
+ id: string;
6
+ name: string;
7
+ checked: boolean;
8
+ onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
9
+ }
10
+
11
+ export const Checkbox = ({
12
+ id,
13
+ name,
14
+ defaultValue,
15
+ defaultChecked,
16
+ checked,
17
+ onChange,
18
+ ...props
19
+ }: CheckboxProps) => {
20
+ return (
21
+ <div className="flex h-6 shrink-0 items-center">
22
+ <div className="group grid size-4 grid-cols-1">
23
+ <input
24
+ {...props}
25
+ id={id}
26
+ name={name}
27
+ type="checkbox"
28
+ defaultValue={defaultValue}
29
+ defaultChecked={defaultChecked}
30
+ checked={checked}
31
+ onChange={onChange}
32
+ className="col-start-1 row-start-1 appearance-none cursor-pointer rounded-sm border border-gray-300 bg-white checked:border-sky-600 checked:bg-sky-600 indeterminate:border-sky-600 indeterminate:bg-sky-600 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-600 disabled:border-gray-300 disabled:bg-gray-100 disabled:checked:bg-gray-100 forced-colors:appearance-auto"
33
+ />
34
+ <svg
35
+ fill="none"
36
+ viewBox="0 0 14 14"
37
+ className="pointer-events-none col-start-1 row-start-1 size-3.5 self-center justify-self-center stroke-white group-has-disabled:stroke-gray-950/25"
38
+ >
39
+ <path
40
+ d="M3 8L6 11L11 3.5"
41
+ strokeWidth={2}
42
+ strokeLinecap="round"
43
+ strokeLinejoin="round"
44
+ className="opacity-0 group-has-checked:opacity-100"
45
+ />
46
+ <path
47
+ d="M3 7H11"
48
+ strokeWidth={2}
49
+ strokeLinecap="round"
50
+ strokeLinejoin="round"
51
+ className="opacity-0 group-has-indeterminate:opacity-100"
52
+ />
53
+ </svg>
54
+ </div>
55
+ </div>
56
+ );
57
+ };
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./Checkbox"
@@ -1,113 +0,0 @@
1
- /* @flow */
2
- import assert from "assert"
3
- import {useEffect, useRef} from "react"
4
- import {Animated, StyleSheet, View, ViewStyle} from "react-native"
5
-
6
- import {withStyles} from "@ui-kitten/components/theme/theme/withStyles"
7
- import {SpinnerAnimation} from "@ui-kitten/components/ui/spinner/animation"
8
-
9
-
10
- type SizeType = {width: number, height: number}
11
-
12
- type ArcElementStyle = {
13
- container: ViewStyle,
14
- arc: ViewStyle,
15
- overflow?: ViewStyle,
16
- }
17
-
18
- const styles = StyleSheet.create({
19
- noOverflow: {
20
- overflow: "hidden",
21
- },
22
- })
23
-
24
- const ActivityIndicator = ({
25
- animating = true,
26
- size = 24,
27
- strokeWidth = 2.6,
28
- duration = 1600,
29
- color = "#007BFF",
30
- testID = "activity-indicator",
31
- style = {},
32
- }) => {
33
- const animationRef = useRef(new SpinnerAnimation(size, {duration}))
34
-
35
- assert(typeof size === "number")
36
-
37
- useEffect(() => {
38
- if (!animationRef.current) {
39
- animationRef.current = new SpinnerAnimation(size, {duration})
40
- }
41
-
42
- return () => {
43
- animationRef.current?.stop()
44
- animationRef.current?.release()
45
- }
46
- }, [size])
47
-
48
- useEffect(() => {
49
- if (animating) {
50
- animationRef.current?.start()
51
- } else {
52
- animationRef.current?.stop()
53
- }
54
- }, [animating])
55
-
56
- const getComponentStyle = (
57
- source: SpinnerAnimation,
58
- ): {start: ArcElementStyle, end: ArcElementStyle} => {
59
- const start: ArcElementStyle = {
60
- container: source.container,
61
- arc: source.start,
62
- }
63
-
64
- const end: ArcElementStyle = {
65
- container: source.container,
66
- arc: source.end,
67
- overflow: {top: size / 2},
68
- }
69
-
70
- return {start, end}
71
- }
72
-
73
- const renderArcElement = (arcStyle: ArcElementStyle): React.Element<typeof View> => {
74
- const arcSize: SizeType = {width: size, height: size / 2}
75
-
76
- const spinnerStyle = {
77
- borderColor: color,
78
- borderRadius: size,
79
- borderWidth: strokeWidth,
80
- height: size,
81
- width: size,
82
- }
83
-
84
- return (
85
- <Animated.View
86
- style={[StyleSheet.absoluteFill, arcStyle.container, {width: size, height: size}]}
87
- >
88
- <View style={[styles.noOverflow, arcStyle.overflow, arcSize]}>
89
- <Animated.View style={[arcStyle.arc, {width: size, height: size}]}>
90
- <View style={[styles.noOverflow, arcSize]}>
91
- <View style={[spinnerStyle]} />
92
- </View>
93
- </Animated.View>
94
- </View>
95
- </Animated.View>
96
- )
97
- }
98
-
99
- if (!animationRef.current) {
100
- return null
101
- }
102
-
103
- const evaStyle = getComponentStyle(animationRef.current?.toProps())
104
-
105
- return (
106
- <View testID={testID} style={{width: size, height: size, ...style}}>
107
- {renderArcElement(evaStyle.start)}
108
- {renderArcElement(evaStyle.end)}
109
- </View>
110
- )
111
- }
112
-
113
- export default withStyles(ActivityIndicator, () => ({}))
@@ -1,4 +0,0 @@
1
- /* @flow */
2
- import {Player} from "@rpcbase/lottie"
3
-
4
- export default Player
@@ -1,8 +0,0 @@
1
- /* @flow */
2
- import withSuspense from "../withSuspense"
3
-
4
-
5
- export default withSuspense(
6
- () => import(/* webpackChunkName: "lottie-player" */ "./LottiePlayer"),
7
- {hideLoader: true},
8
- )
@@ -1,32 +0,0 @@
1
- /* @flow */
2
- import assert from "assert"
3
-
4
- import {useHashState} from "@rpcbase/client/hashState"
5
-
6
-
7
- const HashStateModal = ({hashPropName, children}) => {
8
- const {hashState, serializeHashState} = useHashState()
9
-
10
- if (children) {
11
- assert(typeof children === "function", "HashStateModal children must be a function")
12
- }
13
-
14
- const show = !!hashState[hashPropName]
15
-
16
- console.log("WOWOOW", show)
17
-
18
- if (!show) return null
19
-
20
- const onHide = () => {
21
- serializeHashState({
22
- [hashPropName]: null,
23
- })
24
- }
25
-
26
- const hashProps = {}
27
- hashProps[hashPropName] = hashState[hashPropName]
28
-
29
- return children({onHide, ...hashProps})
30
- }
31
-
32
- export default HashStateModal
package/Modal/Modal.js DELETED
@@ -1,97 +0,0 @@
1
- /* @flow */
2
- import {forwardRef, useEffect, useRef} from "react"
3
- import _debounce from "lodash/debounce"
4
- import BSModal from "react-bootstrap/Modal"
5
-
6
- import "./modal.scss"
7
-
8
-
9
- const MAX_RETRIES = 256
10
- const DELAY_MS = 20
11
-
12
- const Modal = forwardRef(
13
- (
14
- {
15
- show = true,
16
- dark = false,
17
- scrollable = true,
18
- animation = true,
19
- className = "",
20
- children,
21
- ...props
22
- },
23
- _ref,
24
- ) => {
25
- const internalRef = useRef(null)
26
- const ref = _ref || internalRef
27
-
28
- useEffect(() => {
29
- if (!show) return
30
-
31
- let attemptsCount = 0
32
- let ro
33
-
34
- const setup = () => {
35
- const bodyEl = ref.current?.dialog?.querySelector(".modal-body")
36
- if (!bodyEl) {
37
- attemptsCount++
38
- if (attemptsCount > MAX_RETRIES) {
39
- throw new Error("unable to initialize after max attempts")
40
- }
41
- setTimeout(setup, DELAY_MS)
42
- return
43
- }
44
-
45
- const checkApplyScroller = _debounce(() => {
46
- const contentEl = ref.current?.dialog?.querySelector(".modal-content")
47
- // TODO: this shouldn't happen, but it only happens with modalforms... investigate
48
- // additionally we're eventually going to ditch the react-bootstrap modals and use our own so don't waste so much time on this
49
- if (!contentEl) return
50
-
51
- if (bodyEl.scrollHeight > bodyEl.clientHeight) {
52
- if (!contentEl.classList.contains("has-scroller")) {
53
- contentEl.classList.add("has-scroller")
54
- }
55
- } else {
56
- if (contentEl.classList.contains("has-scroller")) {
57
- contentEl.classList.remove("has-scroller")
58
- }
59
- }
60
- }, DELAY_MS)
61
-
62
- ro = new ResizeObserver((entries) => {
63
- checkApplyScroller()
64
- })
65
-
66
- ro.observe(bodyEl)
67
- }
68
-
69
- setup()
70
-
71
- return () => {
72
- ro?.disconnect()
73
- }
74
- }, [show])
75
-
76
- return (
77
- <BSModal
78
- className={cx({"is-dark": dark}, className)}
79
- centered={true}
80
- scrollable={scrollable}
81
- animation={animation}
82
- ref={ref}
83
- show={show}
84
- {...props}
85
- >
86
- {children}
87
- </BSModal>
88
- )
89
- },
90
- )
91
-
92
- Modal.Dialog = BSModal.Dialog
93
- Modal.Header = BSModal.Header
94
- Modal.Body = BSModal.Body
95
- Modal.Footer = BSModal.Footer
96
-
97
- export default Modal
@@ -1,83 +0,0 @@
1
- /* @flow */
2
- import {forwardRef, useImperativeHandle, useState, useEffect} from "react"
3
- import {useFormContext} from "react-hook-form"
4
- import Alert from "react-bootstrap/Alert"
5
-
6
-
7
- const AlertBanner = forwardRef(({modalRef, ...props}, ref) => {
8
- const {formState} = useFormContext()
9
-
10
- const [alertContent, setAlertContent] = useState(null)
11
-
12
- // remove alert if we are done submitting and there are no dirty fields
13
- useEffect(() => {
14
- const hasDirtyFields = Object.keys(formState.dirtyFields).length > 0
15
- if (alertContent && !formState.isSubmitting && !hasDirtyFields) {
16
- setAlertContent(null)
17
- }
18
- }, [alertContent, formState.isSubmitting, formState.dirtyFields])
19
-
20
- const onClickDiscardAndClose = () => {
21
- modalRef.current.forceClose()
22
- }
23
-
24
- const bounce = () => {
25
- requestAnimationFrame(() => {
26
- const el = document.querySelector(".bouncy-alert")
27
-
28
- el.classList.add("bounce")
29
-
30
- setTimeout(() => {
31
- requestAnimationFrame(() => {
32
- el.classList.remove("bounce")
33
- })
34
- // WARNING: timeout must match value in css
35
- }, 220)
36
- })
37
- }
38
-
39
- useImperativeHandle(ref, () => ({
40
- onRequestHide: () => {
41
- const {isSubmitting, dirtyFields} = formState
42
-
43
- // do not close when form submitting
44
- if (isSubmitting) {
45
- setAlertContent(
46
- <Alert variant={"danger"} className="bouncy-alert d-flex">
47
- <div>Cannot close while submitting, please do not close this page.</div>
48
- </Alert>,
49
- )
50
-
51
- bounce()
52
- return false
53
- }
54
- // when form is dirty do not close
55
- else if (Object.keys(dirtyFields).length > 0) {
56
- setAlertContent(
57
- <Alert variant={"light"} className="bouncy-alert d-flex">
58
- <div>Are you sure you want to close without saving?</div>
59
- <div role="button" onClick={onClickDiscardAndClose} className="link-primary ms-2">
60
- Discard and Close
61
- </div>
62
- </Alert>,
63
- )
64
-
65
- bounce()
66
- return false
67
- }
68
-
69
- setAlertContent(null)
70
- return true
71
- },
72
- }))
73
-
74
- return (
75
- <div className="modal-form-alerts w-100" style={{top: -70}}>
76
- {alertContent}
77
- </div>
78
- )
79
- })
80
-
81
- AlertBanner.displayName = "AlertBanner"
82
-
83
- export default AlertBanner
@@ -1,193 +0,0 @@
1
- /* @flow */
2
- import debug from "debug"
3
- import {forwardRef, useImperativeHandle, useEffect, useState, useRef} from "react"
4
- import {FormProvider} from "react-hook-form"
5
-
6
- import ActivityIndicator from "../../ActivityIndicator"
7
- import SubmitButton from "../../SubmitButton"
8
-
9
- import Modal from "../Modal"
10
-
11
- import AlertBanner from "./AlertBanner"
12
-
13
- import "./modal-form.scss"
14
-
15
-
16
- const log = debug("form")
17
-
18
-
19
- const ExtLink = ({to}) => {
20
-
21
- return (
22
- <a target="_blank" rel="noopener noreferrer" href={to}>
23
- {to}
24
- </a>
25
- )
26
- }
27
-
28
-
29
- const SHOW_LOADER_DELAY = 120 // ms
30
-
31
- // Bootstrap Modal integrated with hook form
32
- const ModalForm = forwardRef(
33
- (
34
- {
35
- title,
36
- icon,
37
- footerLink,
38
- submitTitle,
39
- submittingTitle,
40
- show,
41
- onHide,
42
- isLiveSubmit = false,
43
- form,
44
- onSubmit,
45
- children,
46
- ...props
47
- },
48
- _ref,
49
- ) => {
50
- const {formState, watch, handleSubmit} = form
51
-
52
- const internalRef = useRef(null)
53
- const ref = _ref || internalRef
54
-
55
- const alertBannerRef = useRef(null)
56
-
57
- // timeoutRef: only start displaying isBusy after a short delay
58
- // to avoid screen flashing when the data loads fast enough
59
- const timeoutRef = useRef(null)
60
- const [isBusy, setIsBusy] = useState(false)
61
-
62
- useImperativeHandle(ref, () => ({
63
- ...ref.current,
64
- forceClose: () => {
65
- onHide()
66
- },
67
- }))
68
-
69
- useEffect(() => {
70
- // busy when either submitting or loading (async getDefaultValues)
71
- if (formState.isSubmitting || formState.isLoading) {
72
- timeoutRef.current = setTimeout(() => {
73
- setIsBusy(true)
74
- }, SHOW_LOADER_DELAY)
75
- } else {
76
- if (timeoutRef.current) {
77
- window.clearTimeout(timeoutRef.current)
78
- }
79
- setIsBusy(false)
80
- }
81
- }, [formState.isSubmitting, formState.isLoading, setIsBusy])
82
-
83
- useEffect(() => {
84
- if (isLiveSubmit) {
85
- const subscription = watch(handleSubmit(onSubmit))
86
- return () => subscription.unsubscribe()
87
- }
88
- }, [isLiveSubmit, handleSubmit, watch])
89
-
90
- const onHideHandler = () => {
91
- log("onHideHandler")
92
- if (!isLiveSubmit) {
93
- onHide()
94
- return
95
- }
96
-
97
- if (alertBannerRef.current.onRequestHide()) {
98
- onHide()
99
- }
100
- }
101
-
102
- const onClickSubmit = async() => {
103
- log("onClickSubmit")
104
- await handleSubmit(onSubmit)()
105
- }
106
-
107
- return (
108
- <Modal
109
- className="modal-form"
110
- show={show}
111
- onHide={onHideHandler}
112
- ref={ref}
113
- backdrop={isBusy ? "static" : true}
114
- {...props}
115
- >
116
- <FormProvider {...form}>
117
- <AlertBanner ref={alertBannerRef} modalRef={ref} />
118
- <Modal.Header closeButton>
119
- <div>
120
- {icon && (
121
- <img
122
- width={20}
123
- height={20}
124
- style={{marginTop: 0}}
125
- className="me-2"
126
- src={`/static/icons/${icon}.svg`}
127
- />
128
- )}
129
- {title}
130
- </div>
131
- </Modal.Header>
132
- <Modal.Body className="pb-3" style={{position: "relative"}}>
133
- <div className={cx("modal-form-body", {"is-busy": isBusy})}>
134
- <fieldset disabled={isBusy}>{children}</fieldset>
135
- </div>
136
-
137
- {isBusy && (
138
- <div className="loading-overlay">
139
- {isLiveSubmit && (
140
- <>
141
- <ActivityIndicator />
142
- <div className="mt-2 fw-normal">
143
- {formState.isLoading && <>Loading...</>}
144
- {formState.isSubmitting && <>{submittingTitle || "Submitting..."}</>}
145
- </div>
146
- </>
147
- )}
148
- </div>
149
- )}
150
- </Modal.Body>
151
-
152
- {footerLink && isLiveSubmit && (
153
- <Modal.Footer className="justify-content-start bg-light">
154
- For more information, check out&nbsp;
155
- <ExtLink to={footerLink} />
156
- </Modal.Footer>
157
- )}
158
-
159
- {footerLink && !isLiveSubmit && (
160
- <Modal.Footer className="p-0 justify-content-start align-items-start flex-column">
161
- <div className="d-flex flex-row-reverse justify-content-start w-100 py-2">
162
- <SubmitButton
163
- className="me-3"
164
- disabled={formState.isSubmitting || formState.isLoading}
165
- isLoading={formState.isSubmitting}
166
- onClick={onClickSubmit}
167
- >
168
- {formState.isSubmitting ? submittingTitle || submitTitle : submitTitle}
169
- </SubmitButton>
170
-
171
- <button
172
- className="btn btn-link btn-cancel"
173
- disabled={formState.isSubmitting}
174
- onClick={onHideHandler}
175
- >
176
- Cancel
177
- </button>
178
- </div>
179
- <div className="w-100 bg-light border-top mx-0 my-0 p-3">
180
- For more information, check out&nbsp;
181
- <ExtLink to={footerLink} />
182
- </div>
183
- </Modal.Footer>
184
- )}
185
- </FormProvider>
186
- </Modal>
187
- )
188
- },
189
- )
190
-
191
- ModalForm.displayName = "ModalForm"
192
-
193
- export default ModalForm
@@ -1,63 +0,0 @@
1
- @import "helpers";
2
-
3
- @keyframes bounce {
4
- 0% {
5
- transform: scale(1);
6
- }
7
-
8
- 50% {
9
- transform: scale(1.02);
10
- }
11
-
12
- 100% {
13
- transform: scale(1);
14
- }
15
- }
16
-
17
- $bounce-duration: 220ms;
18
-
19
- .modal-form {
20
- .modal-content {
21
- overflow: visible;
22
- }
23
-
24
- .modal-footer {
25
- border-bottom-left-radius: var(--bs-modal-border-radius);
26
- border-bottom-right-radius: var(--bs-modal-border-radius);
27
- overflow: hidden;
28
- }
29
-
30
- .modal-form-body {
31
- &.is-busy {
32
- // doesn't look that good, does it
33
- // filter: blur(0.5px);
34
- opacity: 0.8;
35
- }
36
- }
37
-
38
- .modal-form-alerts {
39
- position: absolute;
40
- top: -40px;
41
- }
42
-
43
- .alert {
44
- border-radius: var(--bs-modal-border-radius);
45
- box-shadow: var(--bs-modal-box-shadow);
46
- }
47
-
48
- .alert.alert-light {
49
- // background: var(--bs-modal-bg) !important;
50
- background: var(--bs-gray-200) !important;
51
- border-color: $gray-700;
52
- opacity: 1;
53
- }
54
-
55
- .bouncy-alert {
56
- transform: scale(1);
57
- transition: transform $bounce-duration ease-out;
58
-
59
- &.bounce {
60
- animation: bounce $bounce-duration;
61
- }
62
- }
63
- }
package/Modal/index.js DELETED
@@ -1,10 +0,0 @@
1
- /* @flow */
2
- import Modal from "./Modal"
3
- import ModalForm from "./ModalForm"
4
- import withHashStateModal from "./withHashStateModal"
5
- import HashStateModal from "./HashStateModal"
6
-
7
-
8
- export {ModalForm, HashStateModal, withHashStateModal}
9
-
10
- export default Modal
package/Modal/modal.scss DELETED
@@ -1,101 +0,0 @@
1
- @import "helpers";
2
-
3
- $navbar-height: 45px !default;
4
-
5
- .modal.is-dark {
6
- $border-color: $gray-800;
7
- $bg-darker: darken($gray-900, 4%);
8
-
9
- .modal-content {
10
- background-color: $gray-900;
11
- color: $gray-100;
12
- border-color: $black;
13
- }
14
-
15
- .modal-header {
16
- color: $gray-400;
17
- background-color: $bg-darker;
18
- border-color: $black;
19
- }
20
-
21
- .modal-footer {
22
- background-color: $bg-darker;
23
- border-color: $black;
24
- }
25
-
26
- .btn-close {
27
- background-color: $gray-700;
28
- }
29
-
30
- .text-secondary {
31
- color: $gray-600 !important;
32
- }
33
-
34
- hr {
35
- border-color: $gray-600;
36
- }
37
- }
38
-
39
- .modal-header {
40
- font-size: 1rem;
41
- font-weight: 600;
42
-
43
- &.close-top {
44
- .btn-close {
45
- align-self: flex-start;
46
- }
47
- }
48
- }
49
-
50
- .fullsize-modal {
51
- .modal-header {
52
- font-size: 15px;
53
-
54
- // padding-top: 10px;
55
- // padding-bottom: 9px;
56
- padding-top: 0;
57
- padding-bottom: 0;
58
-
59
- height: $navbar-height;
60
- }
61
-
62
- .modal-content {
63
- overflow: hidden;
64
- border-top: none;
65
- border-bottom: none;
66
- }
67
-
68
- .modal-dialog {
69
- margin-top: 0;
70
- margin-bottom: 0;
71
- width: 100%;
72
- max-width: calc(100vw - 82px);
73
- height: 100%;
74
- }
75
-
76
- .modal-header,
77
- .modal-content {
78
- border-radius: 0;
79
- }
80
-
81
- // @include media-breakpoint-up(lg) {
82
- @media (min-width: 992px) {
83
- .modal-dialog {
84
- max-width: calc(100vw - 182px) !important;
85
- }
86
- }
87
- }
88
-
89
- @media (height < 600px) {
90
- .modal-content.has-scroller {
91
- border-color: $white !important;
92
- border-radius: 0 !important;
93
- }
94
-
95
- .modal-dialog-centered {
96
- height: 100% !important;
97
- min-height: 100% !important;
98
- margin-top: 0;
99
- margin-bottom: 0;
100
- }
101
- }
@@ -1,24 +0,0 @@
1
- /* @flow */
2
- import {useHashState} from "@rpcbase/client/hashState"
3
-
4
-
5
- const withHashStateModal = (Component, hashPropName) => () => {
6
- const {hashState, serializeHashState} = useHashState()
7
-
8
- const show = !!hashState[hashPropName]
9
-
10
- if (!show) return null
11
-
12
- const onHide = () => {
13
- serializeHashState({
14
- [hashPropName]: null,
15
- })
16
- }
17
-
18
- const hashProps = {}
19
- hashProps[hashPropName] = hashState[hashPropName]
20
-
21
- return <Component onHide={onHide} {...hashProps} />
22
- }
23
-
24
- export default withHashStateModal
@@ -1,32 +0,0 @@
1
- /* @flow */
2
- import ActivityIndicator from "../ActivityIndicator"
3
-
4
-
5
- type Props = {
6
- id?: string,
7
- className: string,
8
- disabled: boolean,
9
- isLoading: boolean,
10
- onClick: Function,
11
- }
12
-
13
- const SubmitButton = ({className = "", id = "btn-submit", ...props}: Props) => (
14
- <button
15
- id={id}
16
- type="submit"
17
- className={cx("submit-button btn btn-primary fw-bold d-flex flex-row align-items-center", className)}
18
- disabled={props.disabled || props.isLoading}
19
- onClick={props.onClick}
20
- >
21
- {props.isLoading && (
22
- <>
23
- <ActivityIndicator style={{marginRight: 6}} color="#FFF" size={15} />
24
-
25
- {props.children}
26
- </>
27
- )}
28
- {!props.isLoading && <>{props.children}</>}
29
- </button>
30
- )
31
-
32
- export default SubmitButton
@@ -1,40 +0,0 @@
1
- /* @flow */
2
- import React, {Suspense, useEffect, useState} from "react"
3
-
4
- import ActivityIndicator from "../ActivityIndicator"
5
-
6
-
7
- const DELAY_BEFORE_LOADER = 200
8
-
9
- const withSuspense = (loadFn, opts = {hideLoader: false}) => {
10
- const Component = React.lazy(loadFn)
11
-
12
- const Loader = () => {
13
- const [showLoader, setShowLoader] = useState(false)
14
-
15
- useEffect(() => {
16
- setTimeout(() => {
17
- setShowLoader(true)
18
- }, DELAY_BEFORE_LOADER)
19
- }, [])
20
-
21
- if (!showLoader || opts.hideLoader) return null
22
-
23
- return (
24
- <div className="d-flex flex-column h-100 justify-content-center align-items-center">
25
- <div className="mb-2">Loading...</div>
26
- <ActivityIndicator />
27
- </div>
28
- )
29
- }
30
-
31
- const Wrapper = React.forwardRef((props, ref) => (
32
- <Suspense fallback={<Loader />}>
33
- <Component ref={ref} {...props} />
34
- </Suspense>
35
- ))
36
-
37
- return Wrapper
38
- }
39
-
40
- export default withSuspense