Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions formulus-formplayer/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -649,9 +649,10 @@ function App() {
<div
style={{
width: process.env.NODE_ENV === 'development' ? '60%' : '100%',
overflow: 'auto',
padding: '20px',
overflow: 'hidden', // Prevent outer scrolling - FormLayout handles scrolling internally
padding: '12px',
boxSizing: 'border-box',
height: '100%', // Ensure it takes full height
}}
>
<ErrorBoundary>
Expand Down
83 changes: 51 additions & 32 deletions formulus-formplayer/src/FormLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,78 +109,89 @@ const FormLayout: React.FC<FormLayoutProps> = ({
sx={{
display: 'flex',
flexDirection: 'column',
height: '100dvh', // Dynamic viewport height - adapts to mobile keyboard
height: '100dvh',
width: '100%',
overflow: 'hidden',
position: 'relative',
// Ensure proper rendering on all devices
WebkitOverflowScrolling: 'touch',
}}
>
{/* Header Area - Sticky at top (optional) */}
{header && (
<Box
sx={{
flexShrink: 0,
position: 'sticky',
top: 0,
zIndex: 10,
zIndex: 100,
backgroundColor: 'background.default',
// Add subtle shadow for visual separation
paddingTop: 'env(safe-area-inset-top, 0px)',
boxShadow: '0 2px 4px rgba(0,0,0,0.05)',
width: '100%',
overflow: 'hidden',
}}
>
{header}
</Box>
)}

{/* Scrollable Content Area */}
<Box
sx={{
sx={(theme) => ({
flex: 1,
overflowY: 'auto',
overflowX: 'hidden',
// Use -webkit-overflow-scrolling for smooth iOS scrolling
WebkitOverflowScrolling: 'touch',
// Add padding to prevent content from being hidden behind navigation
paddingBottom: `${contentBottomPadding}px`,
// Ensure proper scrolling behavior when keyboard appears
paddingBottom:
showNavigation && (previousButton || nextButton) && !isKeyboardVisible
? {
xs: `calc(${theme.spacing(11)} + env(safe-area-inset-bottom, 0px))`,
sm: `calc(${theme.spacing(12)} + env(safe-area-inset-bottom, 0px))`,
md: `calc(${theme.spacing(13)} + env(safe-area-inset-bottom, 0px))`,
}
: theme.spacing(15),
overscrollBehavior: 'contain',
}}
position: 'relative',
})}
>
{children}
</Box>

{/* Navigation Bar - Sticky at bottom, non-overlapping */}
{/* Hide navigation when keyboard is visible to prevent covering content */}
{showNavigation && (previousButton || nextButton) && !isKeyboardVisible && (
<Paper
elevation={3}
sx={{
flexShrink: 0,
position: 'sticky',
elevation={4}
sx={(theme) => ({
position: 'fixed',
bottom: 0,
zIndex: 10,
left: 0,
right: 0,
zIndex: theme.zIndex.appBar,
width: '100%',
padding: { xs: 1.5, sm: 2 },
padding: {
xs: theme.spacing(1.5, 2),
sm: theme.spacing(2, 3),
md: theme.spacing(2.5, 4),
},
paddingBottom: {
xs: `calc(${theme.spacing(1.5)} + env(safe-area-inset-bottom, 0px))`,
sm: `calc(${theme.spacing(2)} + env(safe-area-inset-bottom, 0px))`,
md: `calc(${theme.spacing(2.5)} + env(safe-area-inset-bottom, 0px))`,
},
backgroundColor: 'background.paper',
// Add border-top for visual separation
borderTop: '1px solid',
borderColor: 'divider',
// Ensure it stays above content
boxShadow: '0 -2px 8px rgba(0,0,0,0.1)',
boxShadow: '0 -4px 12px rgba(0,0,0,0.15)',
transition: 'opacity 0.2s ease-in-out, transform 0.2s ease-in-out',
}}
boxSizing: 'border-box',
})}
>
<Stack
direction="row"
spacing={2}
justifyContent="center"
sx={{
// Full-width buttons on mobile, auto-width on larger screens
'& > *': {
flex: { xs: 1, sm: '0 1 auto' },
minWidth: { xs: 'auto', sm: '120px' },
minWidth: { xs: 'auto', sm: '120px', md: '140px' },
maxWidth: { md: '200px' },
},
}}
>
Expand All @@ -191,9 +202,13 @@ const FormLayout: React.FC<FormLayoutProps> = ({
disabled={previousButton.disabled}
fullWidth={false}
sx={{
// Ensure buttons are touch-friendly (Material Design minimum: 48dp)
minHeight: { xs: '48px', sm: '48px' },
fontSize: { xs: '0.875rem', sm: '0.875rem' },
minHeight: { xs: '48px', sm: '48px', md: '52px' },
fontSize: { xs: '0.875rem', sm: '0.875rem', md: '0.9375rem' },
fontWeight: 600,
borderWidth: 2,
'&:hover': {
borderWidth: 2,
},
}}
>
{previousButton.label || 'Previous'}
Expand All @@ -206,9 +221,13 @@ const FormLayout: React.FC<FormLayoutProps> = ({
disabled={nextButton.disabled}
fullWidth={false}
sx={{
// Ensure buttons are touch-friendly (Material Design minimum: 48dp)
minHeight: { xs: '48px', sm: '48px' },
fontSize: { xs: '0.875rem', sm: '0.875rem' },
minHeight: { xs: '48px', sm: '48px', md: '52px' },
fontSize: { xs: '0.875rem', sm: '0.875rem', md: '0.9375rem' },
fontWeight: 600,
boxShadow: 2,
'&:hover': {
boxShadow: 4,
},
}}
>
{nextButton.label || 'Next'}
Expand Down
5 changes: 3 additions & 2 deletions formulus-formplayer/src/FormProgressBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ const FormProgressBar: React.FC<FormProgressBarProps> = ({
sx={{
width: '100%',
mb: 2,
px: { xs: 1, sm: 2 },
px: 0,
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5, px: { xs: 1, sm: 2 } }}>
<LinearProgress
variant="determinate"
value={progress}
Expand All @@ -192,6 +192,7 @@ const FormProgressBar: React.FC<FormProgressBarProps> = ({
textAlign: 'right',
color: 'text.secondary',
fontWeight: 500,
pr: { xs: 1, sm: 2 },
}}
>
{progress}%
Expand Down
2 changes: 1 addition & 1 deletion formulus-formplayer/src/QuestionShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const QuestionShell: React.FC<QuestionShellProps> = ({
)}

{normalizedError && (
<Alert severity="error" sx={{ width: '100%' }}>
<Alert severity="error" sx={{ width: '100%', mb: -1 }}>
{normalizedError}
</Alert>
)}
Expand Down
25 changes: 21 additions & 4 deletions formulus-formplayer/src/index.css
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
html,
body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden; /* Prevent body/html from scrolling - only inner content should scroll */
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

#root {
height: 100%;
overflow: hidden; /* Prevent root from scrolling */
}

.swipelayout_screen {
margin: 0;
padding-top: 2vh;
padding-left: 2%;
padding-right: 2%;
padding-left: 0;
padding-right: 0;
padding-bottom: 2vh;
width: 96%;
/* Remove fixed height and overflow hidden - let FormLayout handle scrolling */
width: 100%;
/* Remove fixed height and overflow - let FormLayout handle scrolling */
min-height: 100%;
box-sizing: border-box;
overflow: visible; /* Ensure no scrolling happens here - only in FormLayout content area */
}

/* Add padding to form content, but not to the container itself */
.swipelayout_screen > div {
padding-left: 1%;
padding-right: 1%;
box-sizing: border-box;
}

.swipelayout_screen > div > div {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"files": {
"main.css": "./static/css/main.c4fc8de5.css",
"main.js": "./static/js/main.2d2937a9.js",
"main.css": "./static/css/main.ce996368.css",
"main.js": "./static/js/main.d5cab582.js",
"index.html": "./index.html",
"main.c4fc8de5.css.map": "./static/css/main.c4fc8de5.css.map",
"main.2d2937a9.js.map": "./static/js/main.2d2937a9.js.map"
"main.ce996368.css.map": "./static/css/main.ce996368.css.map",
"main.d5cab582.js.map": "./static/js/main.d5cab582.js.map"
},
"entrypoints": [
"static/css/main.c4fc8de5.css",
"static/js/main.2d2937a9.js"
"static/css/main.ce996368.css",
"static/js/main.d5cab582.js"
]
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>React App</title><script src="./formulus-load.js"></script><script defer="defer" src="./static/js/main.2d2937a9.js"></script><link href="./static/css/main.c4fc8de5.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="./favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="./logo192.png"/><link rel="manifest" href="./manifest.json"/><title>React App</title><script src="./formulus-load.js"></script><script defer="defer" src="./static/js/main.d5cab582.js"></script><link href="./static/css/main.ce996368.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

This file was deleted.

This file was deleted.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading