Update Convex with no payload to be just like convex with payload but without payload

This commit is contained in:
Gabriel Brown committed 2026-06-21 15:35:42 -05:00
1 parent 13b8b36c4c
commit fba73a92ce
130 files changed
+15637 -32018

No files matched your search

+1 -1
View File
@@ -1 +1 @@
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23"],{"key":"24","value":"25"},{"key":"26","value":"27"},{"key":"28","value":"29"},{"key":"30","value":"31"},{"key":"32","value":"33"},{"key":"34","value":"35"},{"key":"36","value":"37"},{"key":"38","value":"39"},{"key":"40","value":"41"},{"key":"42","value":"43"},{"key":"44","value":"45"},{"key":"46","value":"47"},{"key":"48","value":"49"},{"key":"50","value":"51"},{"key":"52","value":"53"},{"key":"54","value":"55"},{"key":"56","value":"57"},{"key":"58","value":"59"},{"key":"60","value":"61"},{"key":"62","value":"63"},{"key":"64","value":"65"},{"key":"66","value":"67"},{"key":"68","value":"69"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/.gitignore",{"size":16,"mtime":1766222924000,"hash":"70"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/custom/auth/providers/usesend.ts",{"size":3245,"mtime":1774543332725,"hash":"71","data":"72"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/scripts/generateKeys.mjs",{"size":520,"mtime":1768368324432,"hash":"73","data":"74"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/tsconfig.json",{"size":732,"mtime":1766222924000,"hash":"75","data":"76"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/http.ts",{"size":153,"mtime":1768157491000,"hash":"77","data":"78"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/utils.ts",{"size":635,"mtime":1768155639000,"hash":"79","data":"80"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/schema.ts",{"size":1161,"mtime":1774544485430,"hash":"81","data":"82"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/auth.ts",{"size":3770,"mtime":1774537696767,"hash":"83","data":"84"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/files.ts",{"size":582,"mtime":1768239263763,"hash":"85","data":"86"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/custom/auth/index.ts",{"size":142,"mtime":1768157708000,"hash":"87","data":"88"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/types/auth.ts",{"size":174,"mtime":1768188156942,"hash":"89","data":"90"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/crons.ts",{"size":528,"mtime":1768239263662,"hash":"91","data":"92"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/auth.config.ts",{"size":127,"mtime":1768156477000,"hash":"93","data":"94"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/_generated/server.d.ts",{"size":5600,"mtime":1774546246577,"hash":"95","data":"96"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/README.md",{"size":2525,"mtime":1768155639000,"hash":"97","data":"98"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/_generated/api.d.ts",{"size":1632,"mtime":1774546247295,"hash":"99","data":"100"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/_generated/dataModel.d.ts",{"size":1737,"mtime":1774546589762,"hash":"101","data":"102"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/_generated/server.js",{"size":3696,"mtime":1774546246569,"hash":"103","data":"104"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/types/index.ts",{"size":69,"mtime":1768239263861,"hash":"105","data":"106"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/custom/auth/providers/password.ts",{"size":966,"mtime":1774545150633,"hash":"107","data":"108"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/.cache/.prettiercache",{"size":5478,"mtime":1774544663987},"/home/gib/Documents/Code/convex-monorepo/packages/backend/package.json",{"size":1300,"mtime":1768239263823,"hash":"109","data":"110"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/_generated/api.js",{"size":480,"mtime":1774546246582,"hash":"111","data":"112"},"175b1a771387d8b7e26145c3d04e0475","14f5e2d18e21f65282ac744b382f2d5f",{"hashOfOptions":"113"},"ccf5b9105ad4ff66fce0a7133fa3db4b",{"hashOfOptions":"114"},"cfa98923457caed911ec68b626ef4234",{"hashOfOptions":"115"},"4bbb95a66a1e615c30ea7c5098a4a609",{"hashOfOptions":"116"},"6a3198db454396c63e99ee08065726bd",{"hashOfOptions":"117"},"7e6dcc47831030bfaa3e235d2226cec6",{"hashOfOptions":"118"},"3d304208139ef0b2775272a5a4a2a970",{"hashOfOptions":"119"},"5ff3856f1a61b946df899f7c9880b72a",{"hashOfOptions":"120"},"8776a23ed6f2ab3681e4ba5b4bcf3d74",{"hashOfOptions":"121"},"f0f9ef72dc6fef350f3521d3fd8adfc7",{"hashOfOptions":"122"},"0d76c3867783aec5435b0c716f1bfc65",{"hashOfOptions":"123"},"2d4f4ccfc784af9d668d8c64726c2f6b",{"hashOfOptions":"124"},"6719b019702fc173de16b1bdc8e8ed47",{"hashOfOptions":"125"},"f5aa8269478f140adb4ccf0470dd1244",{"hashOfOptions":"126"},"7c522302bfb45e9cf5f1c271b48fa247",{"hashOfOptions":"127"},"ce3275ccdd28673d7e9280b33792057c",{"hashOfOptions":"128"},"f42d53bd1ba24bfee1407d2098f3b9ff",{"hashOfOptions":"129"},"57577de5aadfa618e91739aeLine truncated
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51"],{"key":"52","value":"53"},{"key":"54","value":"55"},{"key":"56","value":"57"},{"key":"58","value":"59"},{"key":"60","value":"61"},{"key":"62","value":"63"},{"key":"64","value":"65"},{"key":"66","value":"67"},{"key":"68","value":"69"},{"key":"70","value":"71"},{"key":"72","value":"73"},{"key":"74","value":"75"},{"key":"76","value":"77"},{"key":"78","value":"79"},{"key":"80","value":"81"},{"key":"82","value":"83"},{"key":"84","value":"85"},{"key":"86","value":"87"},{"key":"88","value":"89"},{"key":"90","value":"91"},{"key":"92","value":"93"},{"key":"94","value":"95"},{"key":"96","value":"97"},{"key":"98","value":"99"},{"key":"100","value":"101"},{"key":"102","value":"103"},{"key":"104","value":"105"},{"key":"106","value":"107"},{"key":"108","value":"109"},{"key":"110","value":"111"},{"key":"112","value":"113"},{"key":"114","value":"115"},{"key":"116","value":"117"},{"key":"118","value":"119"},{"key":"120","value":"121"},{"key":"122","value":"123"},{"key":"124","value":"125"},{"key":"126","value":"127"},{"key":"128","value":"129"},{"key":"130","value":"131"},{"key":"132","value":"133"},{"key":"134","value":"135"},{"key":"136","value":"137"},{"key":"138","value":"139"},{"key":"140","value":"141"},{"key":"142","value":"143"},{"key":"144","value":"145"},{"key":"146","value":"147"},{"key":"148","value":"149"},{"key":"150","value":"151"},{"key":"152","value":"153"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/tsconfig.json",{"size":209,"mtime":1782064673517,"data":"154"},"/home/gib/Documents/Code/Spoon/packages/backend/tsconfig.json",{"size":209,"mtime":1782064673517,"data":"155"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/.gitignore",{"size":16,"mtime":1766222924000,"hash":"156"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/custom/auth/providers/usesend.ts",{"size":3461,"mtime":1782065211116,"hash":"157","data":"158"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/scripts/generateKeys.mjs",{"size":520,"mtime":1768368324432,"hash":"159","data":"160"},"/home/gib/Documents/Code/Spoon/packages/backend/.gitignore",{"size":16,"mtime":1766222924000},"/home/gib/Documents/Code/Spoon/packages/backend/convex/custom/auth/providers/usesend.ts",{"size":3461,"mtime":1782065211116,"data":"161"},"/home/gib/Documents/Code/Spoon/packages/backend/scripts/generateKeys.mjs",{"size":520,"mtime":1768368324432,"data":"162"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/tsconfig.json",{"size":732,"mtime":1766222924000,"hash":"163","data":"164"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/http.ts",{"size":153,"mtime":1768157491000,"hash":"165","data":"166"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/tests/vite-env.d.ts",{"size":38,"mtime":1782064673517,"data":"167"},"/home/gib/Documents/Code/Spoon/packages/backend/convex/http.ts",{"size":153,"mtime":1768157491000,"data":"168"},"/home/gib/Documents/Code/Spoon/packages/backend/convex/tsconfig.json",{"size":732,"mtime":1766222924000,"data":"169"},"/home/gib/Documents/Code/Spoon/packages/backend/tests/vite-env.d.ts",{"size":38,"mtime":1782064673517,"data":"170"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/schema.ts",{"size":1199,"mtime":1774583096378,"hash":"171","data":"172"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/eslint.config.ts",{"size":233,"mtime":1774717251737,"data":"173"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/tests/unit/harness.test.ts",{"size":418,"mtime":1782064673517,"data":"174"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/vitest.config.ts",{"size":387,"mtime":1782065113472,"data":"175"},"/home/gib/Documents/Code/Spoon/packages/backend/convex/schema.ts",{"size":1199,"mtime":1774583096378,"data":"176"},"/home/gib/Documents/Code/Spoon/packages/backend/eslint.config.ts",{"size":233,"mtime":1774717251737,"data":"177"},"/home/gib/Documents/Code/Spoon/packages/backend/tests/unit/harness.test.ts",{"size":418,"mtime":1782064673517,"data":"178"},"/home/gib/Documents/Code/Spoon/packages/backend/vitest.config.ts",{"size":387,"mtime":1782065113472,"data":"179"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/auth.ts",{"size":3664,"mtime":1774717261375,"hash":"180","data":"181"},"/home/gib/Documents/Code/Spoon/packages/backend/convex/auth.ts",{"size":3664,"mtime":1774717261375,"data":"182"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/files.ts",{"size":582,"mtime":1768239263763,"hash":"183","data":"184"},"/home/gib/Documents/Code/convex-monorepo/packages/backend/convex/custom/auth/index.ts",{"size":142,"mtime":1768157708000,"hash":"185","data":"186"},"/home/gib/Documents/Code/Spoon/packages/backend/convex/custom/authLine truncated
-2
View File
@@ -15,7 +15,6 @@ import type * as custom_auth_providers_password from "../custom/auth/providers/p
import type * as custom_auth_providers_usesend from "../custom/auth/providers/usesend.js";
import type * as files from "../files.js";
import type * as http from "../http.js";
import type * as utils from "../utils.js";
import type {
ApiFromModules,
@@ -31,7 +30,6 @@ declare const fullApi: ApiFromModules<{
"custom/auth/providers/usesend": typeof custom_auth_providers_usesend;
files: typeof files;
http: typeof http;
utils: typeof utils;
}>;
/**
+2 -3
View File
@@ -8,7 +8,7 @@ import {
import { ConvexError, v } from 'convex/values';
import type { Doc, Id } from './_generated/dataModel';
import type { MutationCtx, QueryCtx } from './_generated/server';
import type { QueryCtx } from './_generated/server';
import { api } from './_generated/api';
import { action, mutation, query } from './_generated/server';
import { Password, validatePassword } from './custom/auth';
@@ -96,11 +96,10 @@ export const updateUserPassword = action({
if (!userId) throw new ConvexError('Not authenticated.');
const user = await ctx.runQuery(api.auth.getUser, { userId });
if (!user?.email) throw new ConvexError('User not found.');
const verified = await retrieveAccount(ctx, {
await retrieveAccount(ctx, {
provider: 'password',
account: { id: user.email, secret: currentPassword },
});
if (!verified) throw new ConvexError('Current password is incorrect.');
if (!validatePassword(newPassword))
throw new ConvexError('Invalid password.');
@@ -11,32 +11,35 @@ export default function UseSendProvider(config: EmailUserConfig): EmailConfig {
from: process.env.USESEND_FROM_EMAIL ?? '[email protected]',
maxAge: 24 * 60 * 60, // 24 hours
async generateVerificationToken() {
generateVerificationToken: () => {
const random: RandomReader = {
read(bytes) {
crypto.getRandomValues(bytes);
read: (bytes) => {
crypto.getRandomValues(bytes as Uint8Array<ArrayBuffer>);
},
};
return generateRandomString(random, alphabet('0-9'), 6);
},
async sendVerificationRequest(params) {
sendVerificationRequest: async (params) => {
const { identifier: to, provider, url, token } = params;
// Derive a display name from the site URL, fallback to 'App'
const siteUrl = process.env.USESEND_FROM_EMAIL ?? '';
const appName = siteUrl.split('@')[1]?.split('.')[0] ?? 'App';
const useSend = new UseSend(
process.env.USESEND_API_KEY!,
process.env.USESEND_URL!,
);
const apiKey = process.env.USESEND_API_KEY;
const useSendUrl = process.env.USESEND_URL;
if (!apiKey || !useSendUrl) {
throw new Error('USESEND_API_KEY and USESEND_URL must be set.');
}
const useSend = new UseSend(apiKey, useSendUrl);
// For password reset, we want to send the code, not the magic link
const isPasswordReset =
url.includes('reset') || provider.id?.includes('reset');
url.includes('reset') || provider.id.includes('reset');
const result = await useSend.emails.send({
from: provider.from!,
from: provider.from ?? '[email protected]',
to: [to],
subject: isPasswordReset
? `Reset your password - ${appName}`
+10
View File
@@ -0,0 +1,10 @@
// Declare process.env for Convex backend environment variables.
// Convex supports process.env to read variables set in the Convex Dashboard.
declare const process: {
readonly env: {
readonly USESEND_API_KEY?: string;
readonly USESEND_URL?: string;
readonly USESEND_FROM_EMAIL?: string;
readonly [key: string]: string | undefined;
};
};
+1
View File
@@ -18,6 +18,7 @@ const applicationTables = {
phoneVerificationTime: v.optional(v.number()),
isAnonymous: v.optional(v.boolean()),
/* Fields below here are custom & not defined in authTables */
isAdmin: v.optional(v.boolean()),
themePreference: v.optional(
v.union(v.literal('light'), v.literal('dark'), v.literal('system')),
),
-16
View File
@@ -1,16 +0,0 @@
export function missingEnvVariableUrl(envVarName: string, whereToGet: string) {
const deployment = deploymentName();
if (!deployment) return `Missing ${envVarName} in environment variables.`;
return (
`\n Missing ${envVarName} in environment variables.\n\n` +
` Get it from ${whereToGet} .\n Paste it on the Convex dashboard:\n` +
` https://dashboard.convex.dev/d/${deployment}/settings?var=${envVarName}`
);
}
export function deploymentName() {
const url = process.env.CONVEX_CLOUD_URL;
if (!url) return undefined;
const regex = new RegExp('https://(.+).convex.cloud');
return regex.exec(url)?.[1];
}
+10
View File
@@ -0,0 +1,10 @@
import { defineConfig } from 'eslint/config';
import { baseConfig } from '@gib/eslint-config/base';
export default defineConfig(
{
ignores: ['convex/_generated/**', 'types/**', 'scripts/**', 'dist/**'],
},
baseConfig,
);
+15 -6
View File
@@ -14,31 +14,40 @@
"scripts": {
"dev": "bun with-env convex dev",
"dev:tunnel": "bun with-env convex dev",
"dev:web": "bun with-env convex dev",
"setup": "bun with-env convex dev --until-success",
"clean": "git clean -xdf .cache .turbo dist node_modules",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint --flag unstable_native_nodejs_ts_config",
"typecheck": "tsc --noEmit",
"with-env": "dotenv -e ../../.env --"
"test:unit": "vitest run --project unit",
"test:integration": "vitest run --project integration --passWithNoTests",
"test:component": "vitest run --project component --passWithNoTests",
"with-env": "sh ../../scripts/with-env ${INFISICAL_ENV:-dev} --"
},
"dependencies": {
"@oslojs/crypto": "^1.0.1",
"@react-email/components": "0.5.4",
"@react-email/render": "^1.4.0",
"@react-email/components": "1.0.10",
"@react-email/render": "^2.0.4",
"convex": "catalog:convex",
"react": "catalog:react19",
"react-dom": "catalog:react19",
"usesend-js": "^1.5.6",
"usesend-js": "^1.6.3",
"zod": "catalog:"
},
"devDependencies": {
"@edge-runtime/vm": "catalog:test",
"@gib/eslint-config": "workspace:*",
"@gib/prettier-config": "workspace:*",
"@gib/tsconfig": "workspace:*",
"@gib/vitest-config": "workspace:*",
"@types/node": "catalog:",
"convex-test": "catalog:test",
"eslint": "catalog:",
"prettier": "catalog:",
"react-email": "4.2.11",
"typescript": "catalog:"
"react-email": "5.2.10",
"typescript": "catalog:",
"vitest": "catalog:test"
},
"prettier": "@gib/prettier-config"
}
@@ -0,0 +1,13 @@
import { convexTest } from 'convex-test';
import { describe, expect, test } from 'vitest';
import schema from '../../convex/schema';
const modules = import.meta.glob('../../convex/**/*.*s');
describe('convex-test harness', () => {
test('boots and executes against the project schema', async () => {
const t = convexTest(schema, modules);
expect(await t.run(() => Promise.resolve(42))).toBe(42);
});
});
+1
View File
@@ -0,0 +1 @@
/// <reference types="vite/client" />
+6
View File
@@ -0,0 +1,6 @@
{
"extends": "@gib/tsconfig/base.json",
"compilerOptions": { "lib": ["ES2022", "DOM"], "types": ["node"] },
"include": ["tests", "vitest.config.ts"],
"exclude": ["node_modules", "convex/_generated"]
}
+13
View File
@@ -0,0 +1,13 @@
import { defineConfig } from 'vitest/config';
import { convexProject, nodeProject } from '@gib/vitest-config';
export default defineConfig({
test: {
projects: [
convexProject('unit', ['tests/unit/**/*.test.ts']),
convexProject('integration', ['tests/integration/**/*.test.ts']),
nodeProject('component', ['tests/component/**/*.test.{ts,tsx}']),
],
},
});
+1 -1
View File
@@ -1 +1 @@
[{"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/accordion.tsx":"1","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/alert-dialog.tsx":"2","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/alert.tsx":"3","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/aspect-ratio.tsx":"4","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/avatar.tsx":"5","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/badge.tsx":"6","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/based-avatar.tsx":"7","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/based-progress.tsx":"8","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/breadcrumb.tsx":"9","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/button-group.tsx":"10","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/button.tsx":"11","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/calendar.tsx":"12","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/card.tsx":"13","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/carousel.tsx":"14","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/chart.tsx":"15","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/checkbox.tsx":"16","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/collapsible.tsx":"17","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/combobox.tsx":"18","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/command.tsx":"19","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/context-menu.tsx":"20","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dialog.tsx":"21","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/drawer.tsx":"22","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dropdown-menu.tsx":"23","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/empty.tsx":"24","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/field.tsx":"25","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/form.tsx":"26","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/index.tsx":"27","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/use-mobile.ts":"28","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/use-on-click-outside.tsx":"29","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hover-card.tsx":"30","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/image-crop.tsx":"31","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/index.tsx":"32","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input-group.tsx":"33","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input-otp.tsx":"34","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input.tsx":"35","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/item.tsx":"36","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/kbd.tsx":"37","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/label.tsx":"38","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/menubar.tsx":"39","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/native-select.tsx":"40","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/navigation-menu.tsx":"41","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/pagination.tsx":"42","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/popover.tsx":"43","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/progress.tsx":"44","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/radio-group.tsx":"45","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/resizable.tsx":"46","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/scroll-area.tsx":"47","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/select.tsx":"48","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/separator.tsx":"49","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sheet.tsx":"50","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sidebar.tsx":"51","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/skeleton.tsx":"52","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/slider.tsx":"53","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sonner.tsx":"54","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/spinner.tsx":"55","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/status-message.tsx":"56","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/submit-button.tsx":"57","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/switch.tsx":"58","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/table.tsx":"59","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/tabs.tsx":"60","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/textarea.tsx":"61","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/theme.tsx":"62","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/toggle-group.tsx":"63","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/toggle.tsx":"64","/home/gib/Documents/Code/convex-monorepo/pacLine truncated
[{"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/accordion.tsx":"1","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/alert-dialog.tsx":"2","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/alert.tsx":"3","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/aspect-ratio.tsx":"4","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/avatar.tsx":"5","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/badge.tsx":"6","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/based-avatar.tsx":"7","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/based-progress.tsx":"8","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/breadcrumb.tsx":"9","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/button-group.tsx":"10","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/button.tsx":"11","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/calendar.tsx":"12","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/card.tsx":"13","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/carousel.tsx":"14","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/chart.tsx":"15","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/checkbox.tsx":"16","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/collapsible.tsx":"17","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/combobox.tsx":"18","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/command.tsx":"19","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/context-menu.tsx":"20","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/css.d.ts":"21","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dialog.tsx":"22","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/drawer.tsx":"23","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dropdown-menu.tsx":"24","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/empty.tsx":"25","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/field.tsx":"26","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/form.tsx":"27","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/index.tsx":"28","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/use-mobile.ts":"29","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/use-on-click-outside.tsx":"30","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hover-card.tsx":"31","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/image-crop.tsx":"32","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/index.tsx":"33","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input-group.tsx":"34","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input-otp.tsx":"35","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/input.tsx":"36","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/item.tsx":"37","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/kbd.tsx":"38","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/label.tsx":"39","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/menubar.tsx":"40","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/native-select.tsx":"41","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/navigation-menu.tsx":"42","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/pagination.tsx":"43","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/popover.tsx":"44","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/progress.tsx":"45","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/radio-group.tsx":"46","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/resizable.tsx":"47","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/scroll-area.tsx":"48","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/select.tsx":"49","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/separator.tsx":"50","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sheet.tsx":"51","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sidebar.tsx":"52","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/skeleton.tsx":"53","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/slider.tsx":"54","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/sonner.tsx":"55","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/spinner.tsx":"56","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/status-message.tsx":"57","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/submit-button.tsx":"58","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/switch.tsx":"59","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/table.tsx":"60","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/tabs.tsx":"61","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/textarea.tsx":"62","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/theme.tsx":"63","/home/gib/Documents/Code/convex-monorepo/packages/ui/src/toggle-group.tsx":"64","/home/gib/Documents/Code/convex-monorepo/packaLine truncated
+1 -1
View File
@@ -1 +1 @@
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72"],{"key":"73","value":"74"},{"key":"75","value":"76"},{"key":"77","value":"78"},{"key":"79","value":"80"},{"key":"81","value":"82"},{"key":"83","value":"84"},{"key":"85","value":"86"},{"key":"87","value":"88"},{"key":"89","value":"90"},{"key":"91","value":"92"},{"key":"93","value":"94"},{"key":"95","value":"96"},{"key":"97","value":"98"},{"key":"99","value":"100"},{"key":"101","value":"102"},{"key":"103","value":"104"},{"key":"105","value":"106"},{"key":"107","value":"108"},{"key":"109","value":"110"},{"key":"111","value":"112"},{"key":"113","value":"114"},{"key":"115","value":"116"},{"key":"117","value":"118"},{"key":"119","value":"120"},{"key":"121","value":"122"},{"key":"123","value":"124"},{"key":"125","value":"126"},{"key":"127","value":"128"},{"key":"129","value":"130"},{"key":"131","value":"132"},{"key":"133","value":"134"},{"key":"135","value":"136"},{"key":"137","value":"138"},{"key":"139","value":"140"},{"key":"141","value":"142"},{"key":"143","value":"144"},{"key":"145","value":"146"},{"key":"147","value":"148"},{"key":"149","value":"150"},{"key":"151","value":"152"},{"key":"153","value":"154"},{"key":"155","value":"156"},{"key":"157","value":"158"},{"key":"159","value":"160"},{"key":"161","value":"162"},{"key":"163","value":"164"},{"key":"165","value":"166"},{"key":"167","value":"168"},{"key":"169","value":"170"},{"key":"171","value":"172"},{"key":"173","value":"174"},{"key":"175","value":"176"},{"key":"177","value":"178"},{"key":"179","value":"180"},{"key":"181","value":"182"},{"key":"183","value":"184"},{"key":"185","value":"186"},{"key":"187","value":"188"},{"key":"189","value":"190"},{"key":"191","value":"192"},{"key":"193","value":"194"},{"key":"195","value":"196"},{"key":"197","value":"198"},{"key":"199","value":"200"},{"key":"201","value":"202"},{"key":"203","value":"204"},{"key":"205","value":"206"},{"key":"207","value":"208"},{"key":"209","value":"210"},{"key":"211","value":"212"},{"key":"213","value":"214"},{"key":"215","value":"216"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/based-avatar.tsx",{"size":1738,"mtime":1773778628580,"data":"217"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/index.tsx",{"size":104,"mtime":1774538639553,"data":"218"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hover-card.tsx",{"size":1476,"mtime":1774544487157,"data":"219"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/popover.tsx",{"size":2261,"mtime":1774544487690,"data":"220"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/tooltip.tsx",{"size":1771,"mtime":1774544488284,"data":"221"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/aspect-ratio.tsx",{"size":273,"mtime":1774544485059,"data":"222"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/button.tsx",{"size":3380,"mtime":1774544470961,"data":"223"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/toggle-group.tsx",{"size":2238,"mtime":1774544488249,"data":"224"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/hooks/use-mobile.ts",{"size":589,"mtime":1774544470961,"data":"225"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/submit-button.tsx",{"size":1192,"mtime":1773778628581,"data":"226"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/.cache/.eslintcache",{"size":45499,"mtime":1774544652212},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/carousel.tsx",{"size":5758,"mtime":1774544486321,"data":"227"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/textarea.tsx",{"size":736,"mtime":1774544488211,"data":"228"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/.cache/.prettiercache",{"size":13430,"mtime":1774544664111},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/avatar.tsx",{"size":2764,"mtime":1774544485222,"data":"229"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/command.tsx",{"size":4628,"mtime":1774544486715,"data":"230"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dropdown-menu.tsx",{"size":8511,"mtime":1774544486927,"data":"231"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/empty.tsx",{"size":2265,"mtime":1774544486964,"data":"232"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/item.tsx",{"size":4575,"mtime":1774544487439,"data":"233"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/spinner.tsx",{"size":307,"mtime":1774544488097,"data":"234"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/package.json",{"size":2103,"mtime":1774538890797,"data":"235"},"/home/gib/Documents/Code/convex-monorepo/packages/ui/src/dialog.tsx",{"size":3925,"mtime":1774544486830,"data":"236"},"/Line truncated
[["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","69","70","71","72","73","74","75","76","77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98","99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117","118","119","120","121","122","123","124","125","126","127","128","129","130","131","132","133","134","135","136","137","138","139","140","141","142","143","144","145","146","147","148","149"],{"key":"150","value":"151"},{"key":"152","value":"153"},{"key":"154","value":"155"},{"key":"156","value":"157"},{"key":"158","value":"159"},{"key":"160","value":"161"},{"key":"162","value":"163"},{"key":"164","value":"165"},{"key":"166","value":"167"},{"key":"168","value":"169"},{"key":"170","value":"171"},{"key":"172","value":"173"},{"key":"174","value":"175"},{"key":"176","value":"177"},{"key":"178","value":"179"},{"key":"180","value":"181"},{"key":"182","value":"183"},{"key":"184","value":"185"},{"key":"186","value":"187"},{"key":"188","value":"189"},{"key":"190","value":"191"},{"key":"192","value":"193"},{"key":"194","value":"195"},{"key":"196","value":"197"},{"key":"198","value":"199"},{"key":"200","value":"201"},{"key":"202","value":"203"},{"key":"204","value":"205"},{"key":"206","value":"207"},{"key":"208","value":"209"},{"key":"210","value":"211"},{"key":"212","value":"213"},{"key":"214","value":"215"},{"key":"216","value":"217"},{"key":"218","value":"219"},{"key":"220","value":"221"},{"key":"222","value":"223"},{"key":"224","value":"225"},{"key":"226","value":"227"},{"key":"228","value":"229"},{"key":"230","value":"231"},{"key":"232","value":"233"},{"key":"234","value":"235"},{"key":"236","value":"237"},{"key":"238","value":"239"},{"key":"240","value":"241"},{"key":"242","value":"243"},{"key":"244","value":"245"},{"key":"246","value":"247"},{"key":"248","value":"249"},{"key":"250","value":"251"},{"key":"252","value":"253"},{"key":"254","value":"255"},{"key":"256","value":"257"},{"key":"258","value":"259"},{"key":"260","value":"261"},{"key":"262","value":"263"},{"key":"264","value":"265"},{"key":"266","value":"267"},{"key":"268","value":"269"},{"key":"270","value":"271"},{"key":"272","value":"273"},{"key":"274","value":"275"},{"key":"276","value":"277"},{"key":"278","value":"279"},{"key":"280","value":"281"},{"key":"282","value":"283"},{"key":"284","value":"285"},{"key":"286","value":"287"},{"key":"288","value":"289"},{"key":"290","value":"291"},{"key":"292","value":"293"},{"key":"294","value":"295"},{"key":"296","value":"297"},{"key":"298","value":"299"},{"key":"300","value":"301"},{"key":"302","value":"303"},{"key":"304","value":"305"},{"key":"306","value":"307"},{"key":"308","value":"309"},{"key":"310","value":"311"},{"key":"312","value":"313"},{"key":"314","value":"315"},{"key":"316","value":"317"},{"key":"318","value":"319"},{"key":"320","value":"321"},{"key":"322","value":"323"},{"key":"324","value":"325"},{"key":"326","value":"327"},{"key":"328","value":"329"},{"key":"330","value":"331"},{"key":"332","value":"333"},{"key":"334","value":"335"},{"key":"336","value":"337"},{"key":"338","value":"339"},{"key":"340","value":"341"},{"key":"342","value":"343"},{"key":"344","value":"345"},{"key":"346","value":"347"},{"key":"348","value":"349"},{"key":"350","value":"351"},{"key":"352","value":"353"},{"key":"354","value":"355"},{"key":"356","value":"357"},{"key":"358","value":"359"},{"key":"360","value":"361"},{"key":"362","value":"363"},{"key":"364","value":"365"},{"key":"366","value":"367"},{"key":"368","value":"369"},{"key":"370","value":"371"},{"key":"372","value":"373"},{"key":"374","value":"375"},{"key":"376","value":"377"},{"key":"378","value":"379"},{"key":"380","value":"381"},{"key":"382","value":"383"},{"key":"384","value":"385"},{"key":"386","value":"387"},{"key":"388","value":"389"},{"key":"390","value":"391"},{"key":"392","value":"393"},{"key":"394","value":"395"},{"key":"396","value":"397"},{"key":"398","value":"399"},{"key":"400","value":"401"},{"key":"402","value":"403"},{"key":"404","value":"405"},{"key":"406","value":"407"},{"key":"408","value":"409"},{"key":"410","value":"411"},{"key":"412","value":"413"},{"key":"414","value":"415"},{"key":"416","value":"417"},{"key":"418","value":"419"},{"key":"420","value":"421"},{"key":"422","value":"423"},{"key":"424","value":"425"},{"key":"426","value":"427"},{"key":"428","value":"429"},{"key":"430","value":"431"},{"key":"432","value":"433"},{"key":"434","value":"435"},{"key":"436","value":"437"},{"key":"438","value":"439"},{"key":"440","value":"441"},{"key":"442","value":"443"},{"key":"444","value":"445"},{"key":"446","value":"447"},"/home/gib/Documents/Code/convex-monorLine truncated
File diff suppressed because it is too large. Load diff
+18 -9
View File
@@ -12,23 +12,27 @@
"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": {
"@base-ui/react": "^1.3.0",
"@hookform/resolvers": "^5.2.2",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-avatar": "^1.1.11",
"@radix-ui/react-checkbox": "^1.3.3",
"@radix-ui/react-dialog": "^1.1.15",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-label": "^2.1.8",
"@radix-ui/react-progress": "^1.1.8",
"@radix-ui/react-scroll-area": "^1.2.10",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-separator": "^1.1.8",
"@radix-ui/react-slot": "^1.2.4",
"@radix-ui/react-switch": "^1.2.6",
"@radix-ui/react-tabs": "^1.1.13",
"@tabler/icons-react": "^3.41.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
@@ -36,26 +40,31 @@
"embla-carousel-react": "^8.6.0",
"input-otp": "^1.4.2",
"lucide-react": "^0.577.0",
"motion": "^12.38.0",
"next-themes": "^0.4.6",
"radix-ui": "^1.4.3",
"react-day-picker": "^9.14.0",
"react-hook-form": "^7.65.0",
"react-hook-form": "^7.72.0",
"react-image-crop": "^11.0.10",
"react-resizable-panels": "^4",
"recharts": "^3.8.0",
"react-resizable-panels": "^4.7.6",
"recharts": "^3.8.1",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1",
"tailwind-merge": "^3.5.0",
"vaul": "^1.1.2"
},
"devDependencies": {
"@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": {
+3 -3
View File
@@ -4,12 +4,12 @@ import type { ComponentProps } from 'react';
import * as AvatarPrimitive from '@radix-ui/react-avatar';
import { User } from 'lucide-react';
import { AvatarImage, cn } from '@gib/ui';
import { cn } from '@gib/ui';
type BasedAvatarProps = ComponentProps<typeof AvatarPrimitive.Root> & {
src?: string | null;
fullName?: string | null;
imageProps?: Omit<ComponentProps<typeof AvatarImage>, 'data-slot'>;
imageProps?: Omit<ComponentProps<typeof AvatarPrimitive.Image>, 'data-slot'>;
fallbackProps?: ComponentProps<typeof AvatarPrimitive.Fallback>;
userIconProps?: ComponentProps<typeof User>;
};
@@ -35,7 +35,7 @@ const BasedAvatar = ({
{...props}
>
{src ? (
<AvatarImage
<AvatarPrimitive.Image
{...imageProps}
src={src}
className={imageProps?.className}
+1 -1
View File
@@ -45,7 +45,7 @@ const BasedProgress = ({
<ProgressPrimitive.Indicator
data-slot='progress-indicator'
className='bg-primary h-full w-full flex-1 transition-all'
style={{ transform: `translateX(-${100 - (progress ?? 0)}%)` }}
style={{ transform: `translateX(-${100 - progress}%)` }}
/>
</ProgressPrimitive.Root>
);
+2 -3
View File
@@ -98,7 +98,7 @@ const Carousel = ({
api.on('select', onSelect);
return () => {
api?.off('select', onSelect);
api.off('select', onSelect);
};
}, [api, onSelect]);
@@ -108,8 +108,7 @@ const Carousel = ({
carouselRef,
api: api,
opts,
orientation:
orientation || (opts?.axis === 'y' ? 'vertical' : 'horizontal'),
orientation: orientation,
scrollPrev,
scrollNext,
canScrollPrev,
+51 -26
View File
@@ -48,7 +48,7 @@ const ChartContainer = ({
>['children'];
}) => {
const uniqueId = React.useId();
const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`;
const chartId = `chart-${id ?? uniqueId.replace(/:/g, '')}`;
return (
<ChartContext.Provider value={{ config }}>
@@ -72,7 +72,7 @@ const ChartContainer = ({
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
([, config]) => config.theme || config.color,
([, config]) => config.theme ?? config.color,
);
if (!colorConfig.length) {
@@ -89,7 +89,7 @@ ${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ??
itemConfig.color;
return color ? ` --color-${key}: ${color};` : null;
})
@@ -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(() => {
@@ -135,11 +159,11 @@ const ChartTooltipContent = ({
}
const [item] = payload;
const key = `${labelKey || item?.dataKey || item?.name || 'value'}`;
const key = `${labelKey ?? item?.dataKey ?? item?.name ?? 'value'}`;
const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === 'string'
? config[label]?.label || label
? (config[label]?.label ?? label)
: itemConfig?.label;
if (labelFormatter) {
@@ -183,19 +207,19 @@ const ChartTooltipContent = ({
{payload
.filter((item) => item.type !== 'none')
.map((item, index) => {
const key = `${nameKey || item.name || item.dataKey || 'value'}`;
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)
) : (
<>
@@ -232,7 +256,7 @@ const ChartTooltipContent = ({
<div className='grid gap-1.5'>
{nestLabel ? tooltipLabel : null}
<span className='text-muted-foreground'>
{itemConfig?.label || item.name}
{itemConfig?.label ?? item.name}
</span>
</div>
{item.value && (
@@ -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) => {
const key = `${nameKey || item.dataKey || 'value'}`;
.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',
)}
+10 -7
View File
@@ -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} />}
+1
View File
@@ -0,0 +1 @@
declare module '*.css';
+1 -5
View File
@@ -46,10 +46,6 @@ const useFormField = () => {
const formState = useFormState({ name: fieldContext.name });
const fieldState = getFieldState(fieldContext.name, formState);
if (!fieldContext) {
throw new Error('useFormField should be used within <FormField>');
}
const { id } = itemContext;
return {
@@ -138,7 +134,7 @@ const FormDescription = ({
const FormMessage = ({ className, ...props }: React.ComponentProps<'p'>) => {
const { error, formMessageId } = useFormField();
const body = error ? String(error?.message ?? '') : props.children;
const body = error ? String(error.message ?? '') : props.children;
if (!body) {
return null;
@@ -1,5 +1,4 @@
import * as React from 'react';
import { MousePointerClick, X } from 'lucide-react';
type EventType =
| 'mousedown'
+23 -18
View File
@@ -153,7 +153,7 @@ export const ImageCrop = ({
useEffect(() => {
const reader = new FileReader();
reader.addEventListener('load', () =>
setImgSrc(reader.result?.toString() || ''),
setImgSrc(typeof reader.result === 'string' ? reader.result : ''),
);
reader.readAsDataURL(file);
}, [file]);
@@ -173,12 +173,13 @@ export const ImageCrop = ({
onChange?.(pixelCrop, percentCrop);
};
const handleComplete = async (
const handleComplete = (
pixelCrop: PixelCrop,
percentCrop: PercentCrop,
) => {
): Promise<void> => {
setCompletedCrop(pixelCrop);
onComplete?.(pixelCrop, percentCrop);
return Promise.resolve();
};
const applyCrop = async () => {
@@ -293,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>
);
@@ -330,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>
);
@@ -372,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>
+1 -1
View File
@@ -47,7 +47,7 @@ const InputOTPSlot = ({
index: number;
}) => {
const inputOTPContext = React.useContext(OTPInputContext);
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index] ?? {};
return (
<div
+1 -1
View File
@@ -21,7 +21,7 @@ const Progress = ({
<ProgressPrimitive.Indicator
data-slot='progress-indicator'
className='bg-primary size-full flex-1 transition-all'
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
style={{ transform: `translateX(-${100 - (value ?? 0)}%)` }}
/>
</ProgressPrimitive.Root>
);
+3 -3
View File
@@ -602,9 +602,9 @@ const SidebarMenuSkeleton = ({
showIcon?: boolean;
}) => {
// Random width between 50 to 90%.
const width = React.useMemo(() => {
return `${Math.floor(Math.random() * 40) + 50}%`;
}, []);
const [width] = React.useState(
() => `${Math.floor(Math.random() * 40) + 50}%`,
);
return (
<div
+4 -4
View File
@@ -58,13 +58,13 @@ const ToggleGroupItem = ({
return (
<ToggleGroupPrimitive.Item
data-slot='toggle-group-item'
data-variant={context.variant || variant}
data-size={context.size || size}
data-variant={context.variant ?? variant}
data-size={context.size ?? size}
data-spacing={context.spacing}
className={cn(
toggleVariants({
variant: context.variant || variant,
size: context.size || size,
variant: context.variant ?? variant,
size: context.size ?? size,
}),
'w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10',
'data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l',
@@ -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();
});
});
+1
View File
@@ -0,0 +1 @@
import '@testing-library/jest-dom/vitest';
+1 -1
View File
@@ -5,6 +5,6 @@
"jsx": "preserve",
"rootDir": "."
},
"include": ["src"],
"include": ["src", "tests", "vitest.config.ts"],
"exclude": ["node_modules"]
}
+13
View File
@@ -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}']),
],
},
});