I'm wanting to do a checkbox functionality, where you click on the parent checkbox and it checks all the children. But you can also select an individual checkbox. I'm trying to do this using Chakra UI, but in the documentation they do it using just two checkboxes. In my case, I'm using map to iterate, so the problem that occurs is that I can only check them all, but I can't uncheck an individual checkbox. How would I resolve this?
import NextLink from 'next/link';
import { useState } from 'react';
import { queryClient } from '../../services/queryClient';
import { api } from '../../services/api';
export default function UserList() {
const [page, setPage] = useState(1);
const [checkedItems, setCheckedItems] = useState([false, false]);
const allChecked = checkedItems.every(Boolean);
const isIndeterminate = checkedItems.some(Boolean) && !allChecked;
const { data, isLoading, isFetching, error } = useUsers(page);
async function handlePrefetchUser(userId: string) {
await queryClient.prefetchQuery(
['user', userId],
async () => {
const response = await api.get(`users/${userId}`);
return response.data;
},
{
staleTime: 1000 * 60 * 10,
}
);
}
return (
<Box>
<Header />
<Flex my="6" maxWidth={1480} mx="auto" px="6">
<Sidebar />
<Box flex="1" borderRadius={8} bg="gray.800" p="8">
<Flex mb="8" justify="space-between" align="center">
<Heading size="lg" fontWeight="normal">
Alunos
{!isLoading && isFetching && (
<Spinner size="sm" color="gray.500" ml="4" />
)}
</Heading>
<HStack spacing={4}>
<NextLink href="/users/create" passHref>
<Button as="a" size="sm" fontSize="sm" colorScheme="orange">
<Icon as={RiAddLine} fontSize="20" />
</Button>
</NextLink>
<NotificationModal />
<Button
as="a"
size="sm"
fontSize="sm"
colorScheme="green"
cursor="pointer"
>
<Icon as={CgImport} />
</Button>
</HStack>
</Flex>
{isLoading ? (
<Flex justify="center" align="center">
<Spinner />
</Flex>
) : error ? (
<Flex justify="center">
<Text>Falha ao obter dados dos usuários.</Text>
</Flex>
) : (
<>
<Table colorScheme="whiteAlpha">
<Thead>
<Tr>
<Th px={['4', '4', '6']} color="gray.300" w="8">
<Checkbox
colorScheme="orange"
isChecked={allChecked}
isIndeterminate={isIndeterminate}
onChange={(e) =>
setCheckedItems([e.target.checked, e.target.checked])
}
/>
</Th>
<Th>Usuários</Th>
<Th>Ações</Th>
<Th w="8"></Th>
</Tr>
</Thead>
<Tbody>
{data.users.map((user) => (
<Tr key={user.id}>
<Td px={['4', '4', '6']}>
<Checkbox
colorScheme="orange"
isChecked={checkedItems[0]}
onChange={(e) =>
setCheckedItems([e.target.checked, checkedItems[1]])
}
/>
</Td>
<Td>
<Box>
<Link
color="orange.400"
onMouseEnter={() => handlePrefetchUser(user.id)}
>
<Text fontWeight="bold">{user.name}</Text>
</Link>
<Text fontSize="sm" color="gray.300">
{user.email}
</Text>
</Box>
</Td>
<Td>
<Box cursor="pointer">
<HStack spacing={4}>
<Text
color="orange.400"
_hover={{
color: 'orange.500',
}}
>
Editar
</Text>
<Text
color="gray.300"
_hover={{
color: 'gray.500',
}}
>
Excluir
</Text>
</HStack>
</Box>
</Td>
</Tr>
))}
</Tbody>
</Table>
<Pagination
totalCountOfRegisters={data.totalCount}
currentPage={page}
onPageChange={setPage}
/>
</>
)}
</Box>
</Flex>
</Box>
);
}
Here is a simplified example of how to manage an unknown number of child checkboxes:
https://codesandbox.io/s/stupefied-currying-s3r7dr?file=/src/App.js
For your use case, it might be helpful to also move the checkboxes and checkbox state into a child component that only renders once the users are loaded. That would allow you to set the initial checkbox state with the correct number of users.
Related
I'm using logic to check my checkboxes. The functionality allows you to check the parent checkbox and all the children are checked. You can also check or uncheck an individual checkbox. The problem is that I'm using pagination in my component, so if I check the first checkbox on page 1, the first checkbox on page 2 will also be checked. I believe this is because the markup occurs by index. How can I solve this problem?
import { useUsers } from '../../services/hooks/useUsers';
import {
Box,
Button,
Checkbox,
Flex,
Heading,
Icon,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
Text,
useBreakpointValue,
Spinner,
Link,
HStack,
useDisclosure,
} from '#chakra-ui/react';
import { Header } from '../../components/Header';
import { NotificationModal } from '../../components/NotificationModal';
import { Sidebar } from '../../components/Sidebar';
import { RiAddLine } from 'react-icons/ri';
import { CgImport } from 'react-icons/cg';
import { TbEdit } from 'react-icons/tb';
import { FaWhatsapp } from 'react-icons/fa';
import { CgNotes } from 'react-icons/cg';
import { Pagination } from '../../components/Pagination';
import NextLink from 'next/link';
import { useState } from 'react';
import { queryClient } from '../../services/queryClient';
import { api } from '../../services/api';
export default function UserList() {
const [page, setPage] = useState(1);
const { data, isLoading, isFetching, error } = useUsers(page);
const [checkedItems, setCheckedItems] = useState([false]);
const allChecked = checkedItems.every(Boolean);
const isIndeterminate = checkedItems.some(Boolean) && !allChecked;
async function handlePrefetchUser(userId: string) {
await queryClient.prefetchQuery(
['user', userId],
async () => {
const response = await api.get(`users/${userId}`);
return response.data;
},
{
staleTime: 1000 * 60 * 10,
}
);
}
return (
<Box>
<Header />
<Flex my="6" maxWidth={1480} mx="auto" w="94%">
<Sidebar />
<Box flex="1" borderRadius={8} bg="gray.800" p="8" overflow="hidden">
<Flex mb="8" justify="space-between" align="center">
<Heading size="lg" fontWeight="normal">
Alunos
{!isLoading && isFetching && (
<Spinner size="sm" color="gray.500" ml="4" />
)}
</Heading>
<HStack spacing={4}>
<NextLink href="/users/create" passHref>
<Button as="a" size="sm" fontSize="sm" colorScheme="orange">
<Icon as={RiAddLine} fontSize="20" />
</Button>
</NextLink>
<NotificationModal />
<Button
as="a"
size="sm"
fontSize="sm"
colorScheme="blue"
cursor="pointer"
>
<Icon as={CgImport} fontSize="20" />
</Button>
</HStack>
</Flex>
{isLoading ? (
<Flex justify="center" align="center">
<Spinner />
</Flex>
) : error ? (
<Flex justify="center">
<Text>Falha ao obter dados dos usuários.</Text>
</Flex>
) : (
<>
<Table colorScheme="whiteAlpha" overflow="none" size="md">
<Thead>
<Tr>
<Th px={['4', '4', '6']} color="gray.300">
<Checkbox
colorScheme="orange"
isChecked={allChecked}
isIndeterminate={isIndeterminate}
onChange={(e) =>
setCheckedItems(
data.users.map(() => e.target.checked)
)
}
/>
</Th>
<Th w="100%">Alunos</Th>
<Th>Ações</Th>
{/* <Th w="8"></Th> */}
</Tr>
</Thead>
<Tbody>
{data.users.map((user, index) => (
<Tr key={user.id}>
<Td px={['4', '4', '6']}>
<Checkbox
key={user.id}
isChecked={checkedItems[index]}
colorScheme="orange"
onChange={(e) =>
setCheckedItems([
...checkedItems.slice(0, index),
e.target.checked,
...checkedItems.slice(index + 1),
])
}
/>
</Td>
<Td>
<Box>
<Link
color="orange.400"
onMouseEnter={() => handlePrefetchUser(user.id)}
>
<Text fontWeight="bold" fontSize={['sm', 'md']}>
{user.name}
</Text>
</Link>
</Box>
</Td>
<Td>
<Box cursor="pointer">
<HStack spacing={6}>
<Icon
as={TbEdit}
color="gray.400"
fontSize="22"
_hover={{
color: 'white',
}}
/>
<Icon
as={FaWhatsapp}
color="gray.400"
fontSize="22"
_hover={{
color: 'white',
}}
/>
<Icon
as={CgNotes}
color="gray.400"
fontSize="22"
_hover={{
color: 'white',
}}
/>
</HStack>
</Box>
</Td>
</Tr>
))}
</Tbody>
</Table>
<Pagination
totalCountOfRegisters={data.totalCount}
currentPage={page}
onPageChange={setPage}
/>
</>
)}
</Box>
</Flex>
</Box>
);
}
Add a key attribute with a value equal to the page number for the component which wraps your checkboxes.
So when the page number changes the checkboxes component will re-initialize.
I'm using Formik with chakra UI to create dynamic forms using the Fomrik Field array. and I Open my form in Chakra modal, problem is when I open my form in modal it change field name and id to array last object id , When i remove modal its works as expected, I Recreated my problem here
my code sample
<Box>
{/* start card grid */}
<Box py="12" px={{ base: "6", md: "0" }}>
<FormikProvider value={formik}>
<Box as="section" maxW={{ base: "xs", md: "full" }} mx="auto">
<form onSubmit={formik.handleSubmit}>
<SimpleGrid
columns={{ base: 1, sm: 1, md: 3, xl: 4 }}
spacing="6"
>
<FieldArray name="locations">
{() =>
formik.values?.locations?.map(
(props: any, index: string) => {
const { location, reviews } = props;
return (
<>
<Modal
isOpen={isOpen}
onClose={onClose}
>
<ModalOverlay />
<ModalContent>
<ModalCloseButton />
<ModalBody >
<>
<FormLabel>Page URL</FormLabel>
<InputGroup size="md">
<InputLeftAddon
borderTopEndRadius={0}
borderBottomEndRadius={0}
borderColor="grayExtend.300"
bg="grayExtend.100"
fontSize="0.8rem"
px={2}
>
{modal.urlPrefix}
</InputLeftAddon>
<>
<Input
name={`locations.${index}.facebookUrl`}
value={
formik.values.locations[
index
].facebookUrl
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="facebook name"
type="text"
borderWidth="1.5px"
fontSize="0.8rem"
borderColor="grayExtend.300"
borderTopStartRadius={0}
borderBottomStartRadius={
0
}
/>
<Box
fontSize="0.875rem"
color="red"
mt={2}
>
</Box>
</>
</InputGroup>
</>
</ModalBody>
<ModalFooter mb={4}>
<Button
key={`btn${
Math.random() * 1000
}`}
id={modal.web}
colorScheme="blue"
border="1px"
isFullWidth
type="submit"
_hover={{ bg: "#152aa3" }}
disabled={formik.isSubmitting}
>
Submit
</Button>
</ModalFooter>
</ModalContent>
</Modal>
<Flex
direction="column"
alignItems="center"
rounded="md"
padding="8"
position="relative"
shadow="base"
id={index}
>
<Box
position="absolute"
inset="0"
height="20"
roundedTop="inherit"
/>
<VStack
spacing="4"
mt={3}
>
{buttons.map(
({ title, id, icon }) => (
<Button
key={id+1}
id={id}
colorScheme="grayExtend.100"
borderWidth="1px"
borderColor="grayExtend.300"
variant="outline"
p="10px"
borderRadius="4px"
minH="60px"
minW="300px"
onClick={(e) =>
handleOpenModal(e)
}
className={
formik.values.locations[index]
.facebookUrl &&
formik.errors &&
formik.errors.locations &&
getIn(
formik.errors,
`locations.${index}.facebookUrl`
) &&
"success"
}
display="flex"
justifyContent="start"
bg="#f5faff"
fontSize="0.875rem"
>
{title}
</Button>
)
)}
</VStack>
</Flex>
</>
);
}
)
}
</FieldArray>
</SimpleGrid>
</form>
</Box>
</FormikProvider>
</Box>
{/* end card grid */}
</Box>
as I can see you create modal views for each field. This is not a bad solution but it is better to make one modal and give it data to display (I take out the modal component from the map cycle)
Now the main problem to set special data for each button. I add the state new field id.
In formik inputs change values and names to locations[${modal.id}].facebookUrl
The reason, why are you getting last modal is not controlling it's statement. There is now field which says React not to show 2nd,3nd or other components, so there are 4 modals on each other. You can also use your code but add condition which will hide or show your modal view for example
modal.id === idx && <Modal/>
Also link of this code
import {
Box,
useDisclosure,
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalOverlay,
SimpleGrid,
Flex,
VStack,
FormLabel,
Input,
InputGroup,
InputLeftAddon,
ModalFooter
} from "#chakra-ui/react";
import { FieldArray, getIn, useFormik, FormikProvider } from "formik";
import * as React from "react";
const Form = () => {
const [modal, setModal] = React.useState({
web: "",
urlPrefix: "",
id: 0
});
const { isOpen, onOpen, onClose } = useDisclosure();
const cardData: any = {
locations: [
{
facebookUrl: "fb 1"
},
{
facebookUrl: "fb2"
},
{
facebookUrl: ""
},
{
facebookUrl: ""
}
]
};
const buttons = [
{
id: "facebook",
title: "Facebook",
icon: ""
}
];
// modal func
const handleOpenModal = (e: any, idx: number) => {
const { id } = e.target;
if (id === "facebook") {
setModal({
...modal,
web: "facebook",
urlPrefix: "facebook.com",
id: idx
});
} else return null;
onOpen();
return null;
};
const formik = useFormik({
initialValues: cardData,
onSubmit: (values) => {
alert(JSON.stringify(values, null, 2));
}
});
return (
<Box>
{/* start card grid */}
<Box py="12" px={{ base: "6", md: "0" }}>
<FormikProvider value={formik}>
<Box as="section" maxW={{ base: "xs", md: "full" }} mx="auto">
<form onSubmit={formik.handleSubmit}>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalCloseButton />
<ModalBody>
<>
<FormLabel>Page URL</FormLabel>
<InputGroup size="md">
<InputLeftAddon
borderTopEndRadius={0}
borderBottomEndRadius={0}
borderColor="grayExtend.300"
bg="grayExtend.100"
fontSize="0.8rem"
px={2}
>
{modal.urlPrefix}
</InputLeftAddon>
<>
<Input
name={`locations[${modal.id}].facebookUrl`}
value={
formik.values.locations[modal.id].facebookUrl
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder="facebook name"
type="text"
borderWidth="1.5px"
fontSize="0.8rem"
borderColor="grayExtend.300"
borderTopStartRadius={0}
borderBottomStartRadius={0}
/>
<Box fontSize="0.875rem" color="red" mt={2}></Box>
</>
</InputGroup>
</>
</ModalBody>
<ModalFooter mb={4}>
<Button
key={`btn${Math.random() * 1000}`}
id={modal.web}
colorScheme="blue"
border="1px"
isFullWidth
type="submit"
_hover={{ bg: "#152aa3" }}
disabled={formik.isSubmitting}
>
Submit
</Button>
</ModalFooter>
</ModalContent>
</Modal>
<SimpleGrid
columns={{ base: 1, sm: 1, md: 3, xl: 4 }}
spacing="6"
>
<FieldArray name="locations">
{() =>
formik.values?.locations?.map(
(props: any, index: number) => {
const { facebookUrl } = props;
return (
<>
<Flex
direction="column"
alignItems="center"
rounded="md"
padding="8"
position="relative"
shadow="base"
id={index}
>
<Box
position="absolute"
inset="0"
height="20"
roundedTop="inherit"
/>
<VStack spacing="4" mt={3}>
{buttons.map(({ title, id, icon }) => (
<Button
key={id + 1}
id={id}
colorScheme="grayExtend.100"
borderWidth="1px"
borderColor="grayExtend.300"
variant="outline"
p="10px"
borderRadius="4px"
minH="60px"
minW="300px"
onClick={(e) => handleOpenModal(e, index)}
className={
formik.values.locations[index]
.facebookUrl &&
formik.errors &&
formik.errors.locations &&
getIn(
formik.errors,
`locations.${index}.facebookUrl`
) &&
"success"
}
display="flex"
justifyContent="start"
bg="#f5faff"
fontSize="0.875rem"
>
{title}
</Button>
))}
</VStack>
</Flex>
</>
);
}
)
}
</FieldArray>
</SimpleGrid>
</form>
</Box>
</FormikProvider>
</Box>
{/* end card grid */}
</Box>
);
};
export default Form;
My plan is to build a step-by-step from where users can add more sections as needed to a form. This plan is divided into several files to achieve the result, including a parent, a child, and the Quill editor component. I've followed the examples found in the ANT Design website: https://ant.design/components/form/#components-form-demo-dynamic-form-items but failed to replicate the example.
This is the setup for the React-Quill Editor component:
//texteditorsimple.js
import React from 'react';
import ReactQuill, {Quill} from 'react-quill';
import MagicUrl from 'quill-magic-url';
import 'react-quill/dist/quill.snow.css';
//registering magic url module
Quill.register('modules/magicUrl', MagicUrl);
const modules = {
toolbar: [
...
clipboard: {
...
},
magicUrl: true,
};
const formats = [
'list',
'bullet',
'link',
];
const TextEditorSimple = ({ value, onChange, placeholder }) => {
return (
<>
<ReactQuill
theme="snow"
value={value || ''}
modules={modules}
formats={formats}
onChange={onChange}
placeholder={placeholder} >
</ReactQuill>
<div id='counter'></div>
</>
)
}
export default TextEditorSimple;
This is the Parent component:
//parent.js
import React, { useState, useEffect } from 'react';
...
import Child from '../child';
const Parent = () => {
const [ formValue2, setFormValue2 ] = useState([]);
const deleteY = (data) => {
const newArrayFormValue = formValue2.filter(obj => !obj.name.includes(data));
setFormValue2(newArrayFormValue);
}
return (
<Row justify='center' align="top" style={{ padding: 10}}>
<Col>
<Child deleteX={deleteY} fields={formValue2} onChange={(newFields) => {setFormValue2(newFields)}}/>
</Col>
</Row>
)
}
export default Parent;
And this is the Child component:
//child.js
import React from 'react';
...
import TextEditorSimple from './texteditorsimple';
const Child = ({fields, onChange, deleteX}) => {
<Row justify='start' align="top">
<Col xs={24} style={{ padding: 10}}>
<h2>Pengenalan & Langkah-langkah</h2>
<Form
fields={fields}
name="dynamic_form_nest_item"
onFinish={onFinish}
autoComplete="off"
onFieldsChange={(_,allFields) =>{
onChange(allFields);
}} >
<Form.List name="tutorial" style={{ width: '100%'}}>
{(fields, { add, remove }) => (
<>
{fields.map(({ index, key, name, fieldKey, ...restField }) => (
<div key={key}>
<Row>
{
name === 0 ?
<Col xs={24} style={{ padding: 5 }}>
<Form.Item
{...restField}
label='Pengenalan'
name={[name, 'pengenalan']}
fieldKey={[fieldKey, 'pengenalan']}
>
<TextEditorSimple/>
</Form.Item>
</Col>
:
<Col xs={24} md={16} style={{ padding: 5 }}>
<Form.Item
{...restField}
label={'Langkah '+ name}
name={[name, 'langkah'+name]}
fieldKey={[fieldKey, 'langkah'+name]}
>
<TextEditorSimple/>
</Form.Item>
</Col>
}
<Col xs={24} md={8} style={{ padding: 5 }}>
{
name === 0 ?
''
:
<Space align="start">
<Form.Item
{...restField}
name={[name, 'image'+name]}
fieldKey={[fieldKey, 'image'+name]}
valuePropName="fileList"
getValueFromEvent={normFile}
extra="Muat naik satu (1) imej/tangkap layar">
<Upload
name="image"
customRequest={dummyRequest}
listType="picture-card"
maxCount={1} >
{/* <Button icon={<UploadOutlined />}>Muat naik imej/ tangkap layar</Button> */}
{uploadButton}
</Upload>
</Form.Item>
<DeleteOutlined onClick={() => { remove(name); }} style={{ color: 'red'}}/>
</Space>
}
</Col>
</Row>
<Divider/>
</div>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Tambah Langkah
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
</Col>
</Row>
}
export default Child;
I'm trying to catch the changes made on the Form.List 'tutorial' (add, delete) in the Child and uplift the value to the Parent and store them in the state. But the deletion somehow not reflected in the UI, as the element that should have been deleted persisted on page. Tried to manually change the state through poorly coded deleteX and deleteY function, but not successful.
The GIF showing the error can be viewed here: http://www.giphy.com/gifs/HsIjHuckIflqOr3gOO
I'm writing code that empties box from text and replaces that text with new text when link is clicked. But for now it's only adding text below the old text.
This must be done only with JavaScript if possible.
I have tried to find information from everywhere I know and haven't found anything that helps.
Here's my code so far:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import LocalStorageService from '../../../AvainiaTools/LocalStorageService.js';
import AvainiaCore from 'avainia-core-api';
//Components
import ApartmentReview from '../../partials/ApartmentReview/ApartmentReview.js';
//Chakras
import { Box, Divider, Text, Flex, Link } from '#chakra-ui/layout';
import { Image } from '#chakra-ui/image';
class CompanyPage extends Component {
constructor(props) {
super(props);
this.state = {
tab: 'default',
environment: 'environment',
security: 'security',
helps: 'helps',
faqs: 'faqs'
};
}
componentDidMount = () => {
}
render() {
const params = `${this.props.match.params.id}/${this.props.match.params.projectId}`;
const environment = this.state.environment;
const security = this.state.security;
const helps = this.state.helps;
const faqs = this.state.faqs;
return (
<Box bg="white" mb="4">
<Box>
<Box p={[4, 8, 4, 8]}>
<Text fontWeight="bold" fontSize="16">Testdata</Text>
<Divider display={{ base: "none", md: "block"}} width="100%" />
<Box bg="lightgray" p={[4, 8, 4, 8]} ml="800" mt="-4" mb="10">
<Flex mb="4">
<Link
onClick={() => this.setState({ environment: !environment})}
color="black" fontSize="14">Environment</Link>
</Flex>
<Flex mb="4">
<Link
onClick={() => this.setState({ security: !security})}
color="black" fontSize="14">Safety at work</Link>
</Flex>
<Flex mb="4">
<Link
onClick={() => this.setState({ helps: !helps})}
color="black" fontSize="14">Useful Links</Link>
</Flex>
<Link
onClick={() => this.setState({ faqs: !faqs})}
color="black" fontSize="14">FAQ</Link>
</Box>
<Box marginLeft="3">
{ this.state.tab == 'default' &&
<Box bg="white" marginTop="-230" marginRight="445">
<Text fontSize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontSize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontWeight="bold" fontSize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
<br></br>
<Text fontsize="14" margin-left="4">Testdata</Text>
</Box>
}
{this.state.environment !== 'environment' &&
<Box marginRight="445">
<Box bg="white" w="100%">
<Text fontSize="14">Testidata</Text>
</Box>
</Box>
}
{this.state.security !== 'security' &&
<Box marginRight="445">
<Box bg="white" w="100%">
<Text fontSize="14">Testdata</Text>
</Box>
</Box>
}
{this.state.helps !== 'helps' &&
<Box marginRight="445">
<Box bg="white" w="100%">
<Text fontSize="14">Testdata</Text>
</Box>
</Box>
}
{this.state.faqs !== 'faqs' &&
<Box marginRight="445">
<Box bg="white" w="100%">
<Text fontSize="14">Testdata</Text>
</Box>
</Box>
}
</Box>
</Box>
</Box>
<Box p={[4, 8, 4, 8]}>
<Image src="https://via.placeholder.com/1050x195" alt="placeholder" />
</Box>
</Box>
)
}
}
export default withRouter(CompanyPage);
I succeeded to edit the codes of links' onClick so that sub-pages' text replaces original when link is clicked. There's my new link codes:
<Box bg="lightgray" p={[4, 8, 4, 8]} ml="800" mt="-4" mb="10">
<Flex mb="4">
<Link
onClick={() => this.setState({ environment: !environment, tab: !environment})}
color="black" fontSize="14">Environment</Link>
</Flex>
<Flex mb="4">
<Link
onClick={() => this.setState({ security: !security, tab: !security, })}
color="black" fontSize="14">Safety at work</Link>
</Flex>
<Flex mb="4">
<Link
onClick={() => this.setState({ helps: !helps, tab: !helps})}
color="black" fontSize="14">Useful links</Link>
</Flex>
<Link
onClick={() => this.setState({ faqs: !faqs, tab: !faqs})}
color="black" fontSize="14">FAQs</Link>
</Box>
But when I click link in the sub-page, it adds new text below old one. It should replace old sub-page's next with new sub-page's text. How should I edit my code?
When I try to import a layer/button onto one of these cards it does not allow it to be clicked or interacted with. I believe the problem is with the carousel. What is a way I can fix this? The "CenterLayer" is supposed to act as a button and is the one I am having problems with. When I put this code the layer appears on the card as a footer but it's not allowed to be clicked. Is there anyone that can help me with this, please?
import React from "react";
import {
Card,
CardHeader,
CardBody,
CardFooter,
Box,
Image,
Heading,
Carousel,
Grommet,
Calendar,
Text,
} from "grommet";
import {CenterLayer} from "./EventsButton";
import { MainFooter } from "../Footer/Footer";
const Card0 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />
</Box>
</CardHeader>
<CardBody>The Stranahan High School Graduation</CardBody>
<Box direction="row" round gap="xlarge">
<CardFooter>
3/25/2021
</CardFooter>
<CardFooter>
<CenterLayer />
</CardFooter>
</Box>
</Card>
);
const Card1 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />
</Box>
</CardHeader>
<CardBody>Card1 The Stranahan High School Graduation</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
const Card2 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />{" "}
</Box>
</CardHeader>
<CardBody>Card2 The Stranahan High School Graduation</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
const Events = () => (
<Grommet>
<Heading textAlign="center" size="large" alignSelf="center" level="2" margin={{ left: "xlarge",
top: "large",}}>Upcoming Events</Heading>
<Carousel>
<Box direction="row" pad="large" round gap="small">
<Card0 />
<Card1 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card2 />
<Card1 />
<Card0 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
</Carousel>
<Heading textAlign="center" size="large" alignSelf="center" level="2" margin={{ left: "xlarge",
top: "large",}}>Past Events</Heading>
<Carousel>
<Box direction="row" pad="large" round gap="small">
<Card0 />
<Card1 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card2 />
<Card1 />
<Card0 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
</Carousel>
<Box direction="row" pad="xlarge" round gap="xlarge">
<Box height="medium" width="medium" margin={{left: "xlarge"}}>
<Calendar fill daysOfWeek />
</Box>
<Box margin={{left: "xlarge", top:"large"}}>
<Card background={'orange'} >
<CardBody height="medium" width="medium" margin={{right: "medium", bottom: "medium", left: "medium", top: "medium"}}>
<Text>At SEEF we take every opportunity to help the Stranahan community. We hope that our impact will lead others to do the same.</Text>
</CardBody>
</Card>
</Box>
</Box>
< MainFooter />
</Grommet>
);
export default Events
import React from 'react';
import { Add } from 'grommet-icons';
import { Box, Button, Grommet, Heading, Layer, Select, Text } from 'grommet';
import { grommet } from 'grommet/themes';
export const CenterLayer = () => {
const [open, setOpen] = React.useState();
const onOpen = () => setOpen(true);
const onClose = () => setOpen(undefined);
return (
<Grommet theme={grommet} >
<Box fill align="center" justify="center">
<Button
icon={<Add />}
label={
<Text>
<strong>More Information</strong>
</Text>
}
onClick={onOpen}
plain
/>
</Box>
{open && (
<Layer position="center" onClickOutside={onClose} onEsc={onClose}>
<Box pad="medium" gap="small" width="medium">
<Heading level={3} margin="none">
The Stranahan High School Graduation
</Heading>
<Text>This event will be taken place at City Hall in Fort Lauderdale</Text>
<Text>This event will be taken place on 3/25/2021 at 3:00PM</Text>
<Box
as="footer"
gap="small"
direction="row"
align="center"
justify="end"
pad={{ top: 'medium', bottom: 'small' }}
>
<Button
label={
<Text color="white">
<strong>Close</strong>
</Text>
}
onClick={onClose}
primary
color="status-critical"
/>
</Box>
</Box>
</Layer>
)}
</Grommet>
);
};
CenterLayer.storyName = 'Center';
CenterLayer.parameters = {
chromatic: { disable: true },
};
export default {
title: 'EventsButton',
};
Carousel is an interactive element, i.e. it has its own focus and navigation behavior, and for UX & accessibility reasons you shouldn't place nested interactive elements inside of each other, hence I'd try to avoid a button inside of a card, inside of a Carousel.
That being said, the button you've placed in the card is placed 'behind' the Carousel, so moving up its z-index would solve the problem.
Add this style to a Card and it should do trick
<Card style={{ zIndex: "100" }} ... >
I chose 100 as a random number, feel free to make it smaller according to your app behavior.