Move to infisical. Create local dev environment. Add ci gates. Modernize repo
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,9 @@
|
||||
"format": "prettier --check . --ignore-path ../../.gitignore",
|
||||
"lint": "eslint --flag unstable_native_nodejs_ts_config",
|
||||
"typecheck": "tsc --noEmit --emitDeclarationOnly false",
|
||||
"test:unit": "vitest run --project unit --passWithNoTests",
|
||||
"test:integration": "vitest run --project integration --passWithNoTests",
|
||||
"test:component": "NODE_ENV=test vitest run --project component",
|
||||
"ui-add": "bunx --bun shadcn@latest add && prettier src --write --list-different"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -53,11 +56,15 @@
|
||||
"@gib/eslint-config": "workspace:*",
|
||||
"@gib/prettier-config": "workspace:*",
|
||||
"@gib/tsconfig": "workspace:*",
|
||||
"@gib/vitest-config": "workspace:*",
|
||||
"@testing-library/react": "catalog:test",
|
||||
"@types/react": "catalog:react19",
|
||||
"eslint": "catalog:",
|
||||
"jsdom": "catalog:test",
|
||||
"prettier": "catalog:",
|
||||
"react": "catalog:react19",
|
||||
"typescript": "catalog:",
|
||||
"vitest": "catalog:test",
|
||||
"zod": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -21,7 +21,7 @@ const BasedProgress = ({
|
||||
value = 0,
|
||||
...props
|
||||
}: BasedProgressProps) => {
|
||||
const [progress, setProgress] = React.useState<number>(value);
|
||||
const [progress, setProgress] = React.useState<number>(value ?? 0);
|
||||
|
||||
React.useEffect(() => {
|
||||
const id = window.setInterval(() => {
|
||||
|
||||
+44
-19
@@ -105,6 +105,15 @@ ${colorConfig
|
||||
|
||||
const ChartTooltip = RechartsPrimitive.Tooltip;
|
||||
|
||||
type ChartPayloadItem = {
|
||||
name?: string | number;
|
||||
value?: number | string;
|
||||
dataKey?: string | number;
|
||||
type?: string;
|
||||
color?: string;
|
||||
payload?: Record<string, unknown> & { fill?: string };
|
||||
};
|
||||
|
||||
const ChartTooltipContent = ({
|
||||
active,
|
||||
payload,
|
||||
@@ -119,14 +128,29 @@ const ChartTooltipContent = ({
|
||||
color,
|
||||
nameKey,
|
||||
labelKey,
|
||||
}: React.ComponentProps<typeof RechartsPrimitive.Tooltip> &
|
||||
React.ComponentProps<'div'> & {
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: 'line' | 'dot' | 'dashed';
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}) => {
|
||||
}: React.ComponentProps<'div'> & {
|
||||
active?: boolean;
|
||||
payload?: ChartPayloadItem[];
|
||||
label?: React.ReactNode;
|
||||
labelFormatter?: (
|
||||
value: React.ReactNode,
|
||||
payload: ChartPayloadItem[],
|
||||
) => React.ReactNode;
|
||||
formatter?: (
|
||||
value: number | string,
|
||||
name: string | number,
|
||||
item: ChartPayloadItem,
|
||||
index: number,
|
||||
itemPayload: ChartPayloadItem['payload'],
|
||||
) => React.ReactNode;
|
||||
color?: string;
|
||||
labelClassName?: string;
|
||||
hideLabel?: boolean;
|
||||
hideIndicator?: boolean;
|
||||
indicator?: 'line' | 'dot' | 'dashed';
|
||||
nameKey?: string;
|
||||
labelKey?: string;
|
||||
}) => {
|
||||
const { config } = useChart();
|
||||
|
||||
const tooltipLabel = React.useMemo(() => {
|
||||
@@ -139,7 +163,7 @@ const ChartTooltipContent = ({
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||
const value =
|
||||
!labelKey && typeof label === 'string'
|
||||
? config[label]?.label ?? label
|
||||
? (config[label]?.label ?? label)
|
||||
: itemConfig?.label;
|
||||
|
||||
if (labelFormatter) {
|
||||
@@ -185,17 +209,17 @@ const ChartTooltipContent = ({
|
||||
.map((item, index) => {
|
||||
const key = `${nameKey ?? item.name ?? item.dataKey ?? 'value'}`;
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||
const indicatorColor = color ?? item.payload.fill ?? item.color;
|
||||
const indicatorColor = color ?? item.payload?.fill ?? item.color;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.dataKey}
|
||||
key={item.dataKey ?? index}
|
||||
className={cn(
|
||||
'[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5',
|
||||
indicator === 'dot' && 'items-center',
|
||||
)}
|
||||
>
|
||||
{formatter && item?.value !== undefined && item.name ? (
|
||||
{formatter && item.value !== undefined && item.name ? (
|
||||
formatter(item.value, item.name, item, index, item.payload)
|
||||
) : (
|
||||
<>
|
||||
@@ -259,11 +283,12 @@ const ChartLegendContent = ({
|
||||
payload,
|
||||
verticalAlign = 'bottom',
|
||||
nameKey,
|
||||
}: React.ComponentProps<'div'> &
|
||||
Pick<RechartsPrimitive.LegendProps, 'payload' | 'verticalAlign'> & {
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}) => {
|
||||
}: React.ComponentProps<'div'> & {
|
||||
payload?: ChartPayloadItem[];
|
||||
verticalAlign?: 'top' | 'bottom';
|
||||
hideIcon?: boolean;
|
||||
nameKey?: string;
|
||||
}) => {
|
||||
const { config } = useChart();
|
||||
|
||||
if (!payload?.length) {
|
||||
@@ -280,13 +305,13 @@ const ChartLegendContent = ({
|
||||
>
|
||||
{payload
|
||||
.filter((item) => item.type !== 'none')
|
||||
.map((item) => {
|
||||
.map((item, index) => {
|
||||
const key = `${nameKey ?? item.dataKey ?? 'value'}`;
|
||||
const itemConfig = getPayloadConfigFromPayload(config, item, key);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.value}
|
||||
key={item.value ?? index}
|
||||
className={cn(
|
||||
'[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3',
|
||||
)}
|
||||
|
||||
@@ -68,13 +68,16 @@ const ComboboxInput = ({
|
||||
/>
|
||||
<InputGroupAddon align='inline-end'>
|
||||
{showTrigger && (
|
||||
<InputGroupButton
|
||||
size='icon-xs'
|
||||
variant='ghost'
|
||||
render={<ComboboxTrigger />}
|
||||
data-slot='input-group-button'
|
||||
className='group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent'
|
||||
disabled={disabled}
|
||||
<ComboboxTrigger
|
||||
render={
|
||||
<InputGroupButton
|
||||
size='icon-xs'
|
||||
variant='ghost'
|
||||
data-slot='input-group-button'
|
||||
className='group-has-data-[slot=combobox-clear]/input-group:hidden data-pressed:bg-transparent'
|
||||
disabled={disabled}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{showClear && <ComboboxClear disabled={disabled} />}
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
declare module '*.css';
|
||||
@@ -294,19 +294,17 @@ export const ImageCropApply = ({
|
||||
|
||||
if (asChild) {
|
||||
return (
|
||||
<Slot.Root onClick={handleClick} {...(props as any)}>
|
||||
<Slot.Root
|
||||
onClick={handleClick}
|
||||
{...(props as ComponentProps<typeof Slot.Root>)}
|
||||
>
|
||||
{children}
|
||||
</Slot.Root>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
size='icon'
|
||||
variant='ghost'
|
||||
{...(props as any)}
|
||||
>
|
||||
<Button onClick={handleClick} size='icon' variant='ghost' {...props}>
|
||||
{children ?? <CropIcon className='size-4' />}
|
||||
</Button>
|
||||
);
|
||||
@@ -331,19 +329,17 @@ export const ImageCropReset = ({
|
||||
|
||||
if (asChild) {
|
||||
return (
|
||||
<Slot.Root onClick={handleClick} {...(props as any)}>
|
||||
<Slot.Root
|
||||
onClick={handleClick}
|
||||
{...(props as ComponentProps<typeof Slot.Root>)}
|
||||
>
|
||||
{children}
|
||||
</Slot.Root>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
size='icon'
|
||||
variant='ghost'
|
||||
{...(props as any)}
|
||||
>
|
||||
<Button onClick={handleClick} size='icon' variant='ghost' {...props}>
|
||||
{children ?? <RotateCcwIcon className='size-4' />}
|
||||
</Button>
|
||||
);
|
||||
@@ -373,7 +369,15 @@ export const Cropper = ({
|
||||
onChange={onChange}
|
||||
onComplete={onComplete}
|
||||
onCrop={onCrop}
|
||||
{...(props as any)}
|
||||
{...(props as Omit<
|
||||
ImageCropProps,
|
||||
| 'file'
|
||||
| 'maxImageSize'
|
||||
| 'onChange'
|
||||
| 'onComplete'
|
||||
| 'onCrop'
|
||||
| 'children'
|
||||
>)}
|
||||
>
|
||||
<ImageCropContent className={className} style={style} />
|
||||
</ImageCrop>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { Button } from '../../src/button';
|
||||
|
||||
describe('Button', () => {
|
||||
it('renders its children', () => {
|
||||
render(<Button>Click me</Button>);
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'Click me' }),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
@@ -5,6 +5,6 @@
|
||||
"jsx": "preserve",
|
||||
"rootDir": "."
|
||||
},
|
||||
"include": ["src"],
|
||||
"include": ["src", "tests", "vitest.config.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
|
||||
import { jsdomProject, nodeProject } from '@gib/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
projects: [
|
||||
nodeProject('unit', ['tests/unit/**/*.test.{ts,tsx}']),
|
||||
nodeProject('integration', ['tests/integration/**/*.test.{ts,tsx}']),
|
||||
jsdomProject('component', ['tests/component/**/*.test.{ts,tsx}']),
|
||||
],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user