このコミットが含まれているのは:
@@ -25,7 +25,7 @@ type Props = Omit<ComponentPropsWithoutRef<'input'>, 'onChange'> & {
|
||||
onBlur?: (ev: FocusEvent<HTMLInputElement>) => void }
|
||||
|
||||
|
||||
export default (({ value, onChange, className, onBlur, ...rest }: Props) => {
|
||||
const DateTimeField: FC<Props> = ({ value, onChange, className, onBlur, ...rest }) => {
|
||||
const [local, setLocal] = useState ('')
|
||||
|
||||
useEffect (() => {
|
||||
@@ -44,4 +44,6 @@ export default (({ value, onChange, className, onBlur, ...rest }: Props) => {
|
||||
onChange?.(v ? (new Date (v)).toISOString () : null)
|
||||
}}
|
||||
onBlur={onBlur}/>)
|
||||
}) satisfies FC<Props>
|
||||
}
|
||||
|
||||
export default DateTimeField
|
||||
@@ -3,7 +3,9 @@ import type { FC, ReactNode } from 'react'
|
||||
type Props = { children: ReactNode }
|
||||
|
||||
|
||||
export default (({ children }: Props) => (
|
||||
const Form: FC<Props> = ({ children }) => (
|
||||
<div className="max-w-xl mx-auto p-4 space-y-4">
|
||||
{children}
|
||||
</div>)) satisfies FC<Props>
|
||||
</div>)
|
||||
|
||||
export default Form
|
||||
@@ -1,12 +1,14 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
type Props = { children: React.ReactNode
|
||||
checkBox?: { label: string
|
||||
checked: boolean
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void } }
|
||||
|
||||
|
||||
export default ({ children, checkBox }: Props) => {
|
||||
const Label: FC<Props> = ({ children, checkBox }) => {
|
||||
if (!(checkBox))
|
||||
{
|
||||
return (
|
||||
@@ -26,3 +28,5 @@ export default ({ children, checkBox }: Props) => {
|
||||
</label>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default Label
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import PageTitle from '@/components/common/PageTitle'
|
||||
|
||||
|
||||
describe ('PageTitle', () => {
|
||||
it ('renders children as a level 1 heading', () => {
|
||||
render (<PageTitle>Test title</PageTitle>)
|
||||
|
||||
const heading = screen.getByRole ('heading', { level: 1 })
|
||||
|
||||
expect (heading.textContent).toBe ('Test title')
|
||||
})
|
||||
})
|
||||
@@ -1,9 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
type Props = { children: React.ReactNode }
|
||||
|
||||
|
||||
export default ({ children }: Props) => (
|
||||
const PageTitle: FC<Props> = ({ children }) => (
|
||||
<h1 className="text-2xl font-bold mb-2">
|
||||
{children}
|
||||
</h1>)
|
||||
|
||||
export default PageTitle
|
||||
|
||||
@@ -48,7 +48,7 @@ const getPages = (
|
||||
}
|
||||
|
||||
|
||||
export default (({ page, totalPages, siblingCount = 3 }) => {
|
||||
const Pagination: FC<Props> = ({ page, totalPages, siblingCount = 3 }) => {
|
||||
const location = useLocation ()
|
||||
|
||||
const buildTo = (p: number) => {
|
||||
@@ -124,4 +124,6 @@ export default (({ page, totalPages, siblingCount = 3 }) => {
|
||||
</>)}
|
||||
</div>
|
||||
</nav>)
|
||||
}) satisfies FC<Props>
|
||||
}
|
||||
|
||||
export default Pagination
|
||||
|
||||
@@ -5,7 +5,9 @@ import type { ComponentPropsWithoutRef, FC } from 'react'
|
||||
type Props = ComponentPropsWithoutRef<'h2'>
|
||||
|
||||
|
||||
export default (({ children, className, ...rest }: Props) => (
|
||||
const SectionTitle: FC<Props> = ({ children, className, ...rest }) => (
|
||||
<h2 {...rest} className={cn ('text-xl my-4', className)}>
|
||||
{children}
|
||||
</h2>)) satisfies FC<Props>
|
||||
</h2>)
|
||||
|
||||
export default SectionTitle
|
||||
@@ -1,9 +1,13 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { FC } from 'react'
|
||||
|
||||
type Props = { children: React.ReactNode }
|
||||
|
||||
|
||||
export default ({ children }: Props) => (
|
||||
const SubsectionTitle: FC<Props> = ({ children }) => (
|
||||
<h3 className="my-2">
|
||||
{children}
|
||||
</h3>)
|
||||
|
||||
export default SubsectionTitle
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { FC } from 'react'
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
@@ -10,7 +12,7 @@ type Props = { children: React.ReactNode }
|
||||
export const Tab = ({ children }: TabProps) => <>{children}</>
|
||||
|
||||
|
||||
export default ({ children }: Props) => {
|
||||
const TabGroup: FC<Props> = ({ children }) => {
|
||||
const tabs = React.Children.toArray (children) as React.ReactElement<TabProps>[]
|
||||
|
||||
const [current, setCurrent] = useState<number> (() => {
|
||||
@@ -37,3 +39,5 @@ export default ({ children }: Props) => {
|
||||
</div>
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default TabGroup
|
||||
|
||||
@@ -12,7 +12,7 @@ type Props = {
|
||||
value: string
|
||||
setValue: (value: string) => void }
|
||||
|
||||
export default (({ value, setValue }: Props) => {
|
||||
const TagInput: FC<Props> = ({ value, setValue }) => {
|
||||
const [activeIndex, setActiveIndex] = useState (-1)
|
||||
const [suggestions, setSuggestions] = useState<Tag[]> ([])
|
||||
const [suggestionsVsbl, setSuggestionsVsbl] = useState (false)
|
||||
@@ -62,9 +62,12 @@ export default (({ value, setValue }: Props) => {
|
||||
case 'Enter':
|
||||
if (activeIndex < 0)
|
||||
break
|
||||
ev.preventDefault ()
|
||||
const selected = suggestions[activeIndex]
|
||||
selected && handleTagSelect (selected)
|
||||
{
|
||||
ev.preventDefault ()
|
||||
const selected = suggestions[activeIndex]
|
||||
if (selected)
|
||||
handleTagSelect (selected)
|
||||
}
|
||||
break
|
||||
|
||||
case 'Escape':
|
||||
@@ -94,4 +97,6 @@ export default (({ value, setValue }: Props) => {
|
||||
activeIndex={activeIndex}
|
||||
onSelect={handleTagSelect}/>
|
||||
</div>)
|
||||
}) satisfies FC<Props>
|
||||
}
|
||||
|
||||
export default TagInput
|
||||
新しい課題から参照
ユーザをブロックする