mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-09-06 22:49:29 +00:00
A schedule's time was three dropdowns side by side: hour, minute, meridiem. That is three controls for one value, it cannot be read at a glance, and the minute list was a fixed set of four with the stored value bolted on, so a schedule already running at :07 could be kept but never chosen. They become one TimePicker: hour, minute and, where the clock format calls for one, meridiem, as scrollable columns behind a single trigger showing the selected time. An hourly cadence gets MinutePicker, the same control with its other columns dropped, so it reads as the same widget rather than a different one. Both live in packages/client with their wording passed in as props, so the primitive carries no translation keys of its own. Not `<input type="time">`: the browser owns its rendering, and it cannot be brought in line with the rest of the form. `hour12` is a required prop rather than a locale-derived guess. The app has already resolved its Clock format setting, and re-deriving the answer inside the picker would let it disagree with the summary printed beside it. The trigger names its selected value as well as its field: `aria-labelledby` replaces a button's child text, so pointing it at the label alone announced "Time" and left a screen reader user unable to tell what was selected without opening the columns and reading them. The columns are a roving-tabindex radiogroup, arrow keys wrap, and the selected row is scrolled to the middle of its column on open. The popover is deliberately not portaled. A Radix dialog sets `pointer-events: none` on the body while open, so a popover portaled out of it renders correctly but receives no clicks or wheel events, and its focus trap puts the content out of tab order too. Hour and minute are set in one change. Behind separate fields a half-applied edit could submit a time the user never picked, and the form now carries the hour as the 0-23 value the cadence stores rather than a 12-hour value plus a meridiem it has to recombine.
124 lines
3.9 KiB
JSON
124 lines
3.9 KiB
JSON
{
|
|
"name": "@librechat/client",
|
|
"version": "0.4.76",
|
|
"description": "React components for LibreChat",
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "https://github.com/danny-avila/LibreChat"
|
|
},
|
|
"main": "dist/index.cjs",
|
|
"module": "dist/index.mjs",
|
|
"types": "./dist/index.d.cts",
|
|
"exports": {
|
|
".": {
|
|
"import": {
|
|
"types": "./dist/index.d.mts",
|
|
"default": "./dist/index.mjs"
|
|
},
|
|
"require": {
|
|
"types": "./dist/index.d.cts",
|
|
"default": "./dist/index.cjs"
|
|
}
|
|
},
|
|
"./tailwind-preset": "./tailwind.preset.cjs",
|
|
"./style.css": "./dist/style.css",
|
|
"./package.json": "./package.json"
|
|
},
|
|
"files": [
|
|
"dist",
|
|
"tailwind.preset.cjs"
|
|
],
|
|
"scripts": {
|
|
"clean": "rimraf dist",
|
|
"b:clean": "bun run rimraf dist",
|
|
"build": "npm run clean && tsdown",
|
|
"build:dev": "npm run clean && NODE_ENV=development tsdown",
|
|
"b:build": "bun run b:clean && bun run tsdown",
|
|
"build:watch": "tsdown --watch",
|
|
"dev": "tsdown --watch",
|
|
"test": "jest",
|
|
"test:ci": "jest --ci"
|
|
},
|
|
"peerDependencies": {
|
|
"@ariakit/react": "^0.4.29",
|
|
"@ariakit/react-components": "^0.1.2",
|
|
"@dicebear/collection": "^9.4.1",
|
|
"@dicebear/core": "^9.4.1",
|
|
"@headlessui/react": "^2.1.2",
|
|
"@radix-ui/react-accordion": "^1.2.11",
|
|
"@radix-ui/react-alert-dialog": "1.0.2",
|
|
"@radix-ui/react-checkbox": "^1.0.3",
|
|
"@radix-ui/react-collapsible": "^1.1.11",
|
|
"@radix-ui/react-dialog": "1.0.2",
|
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
|
"@radix-ui/react-hover-card": "^1.0.5",
|
|
"@radix-ui/react-icons": "^1.3.0",
|
|
"@radix-ui/react-label": "^2.1.7",
|
|
"@radix-ui/react-popover": "^1.0.7",
|
|
"@radix-ui/react-progress": "^1.1.2",
|
|
"@radix-ui/react-radio-group": "^1.3.7",
|
|
"@radix-ui/react-select": "^2.2.5",
|
|
"@radix-ui/react-separator": "^1.1.7",
|
|
"@radix-ui/react-slider": "^1.3.5",
|
|
"@radix-ui/react-slot": "^1.0.0",
|
|
"@radix-ui/react-switch": "^1.2.5",
|
|
"@radix-ui/react-tabs": "^1.0.3",
|
|
"@radix-ui/react-toast": "^1.1.5",
|
|
"@rc-component/mini-decimal": "^1.0.1",
|
|
"@react-spring/web": "^10.0.1",
|
|
"@tanstack/react-query": "^4.28.0 || ^5.0.0",
|
|
"@tanstack/react-table": "^8.11.7",
|
|
"@tanstack/react-virtual": "^3.0.0",
|
|
"class-variance-authority": "^0.7.1",
|
|
"clsx": "^2.1.1",
|
|
"dompurify": "^3.4.0",
|
|
"framer-motion": "^12.40.0",
|
|
"i18next": "^24.2.2 || ^25.3.2",
|
|
"i18next-browser-languagedetector": "^8.2.0",
|
|
"input-otp": "^1.4.2",
|
|
"jotai": "^2.12.5",
|
|
"librechat-data-provider": "*",
|
|
"lucide-react": "^0.525.0",
|
|
"match-sorter": "^8.1.0",
|
|
"rc-input-number": "^7.4.2",
|
|
"react": "^18.2.0 || ^19.1.0",
|
|
"react-dom": "^18.2.0 || ^19.1.0",
|
|
"react-hook-form": "^7.56.4",
|
|
"react-i18next": "^15.4.0 || ^15.6.0",
|
|
"react-resizable-panels": "^4.7.4",
|
|
"react-textarea-autosize": "^8.4.0",
|
|
"tailwind-merge": "^1.9.1"
|
|
},
|
|
"devDependencies": {
|
|
"@babel/core": "^7.28.5",
|
|
"@babel/preset-env": "^7.29.5",
|
|
"@babel/preset-react": "^7.28.5",
|
|
"@babel/preset-typescript": "^7.28.5",
|
|
"@tanstack/react-query": "^4.28.0",
|
|
"@tanstack/react-table": "^8.21.3",
|
|
"@tanstack/react-virtual": "^3.13.13",
|
|
"@testing-library/jest-dom": "^6.9.1",
|
|
"@testing-library/react": "^14.0.0",
|
|
"@tsdown/css": "^0.22.2",
|
|
"@types/jest": "^29.5.14",
|
|
"@types/react": "^18.2.11",
|
|
"@types/react-dom": "^18.2.4",
|
|
"babel-jest": "^30.2.0",
|
|
"caniuse-lite": "^1.0.30001741",
|
|
"i18next": "^24.2.3",
|
|
"identity-obj-proxy": "^3.0.0",
|
|
"jest": "^30.2.0",
|
|
"jest-environment-jsdom": "^30.2.0",
|
|
"jotai": "^2.12.5",
|
|
"librechat-data-provider": "*",
|
|
"lucide-react": "^0.525.0",
|
|
"react": "^18.2.0",
|
|
"react-dom": "^18.2.0",
|
|
"react-i18next": "^15.4.0",
|
|
"rimraf": "^6.1.3",
|
|
"tailwindcss": "^3.4.1",
|
|
"tailwindcss-radix": "^2.8.0",
|
|
"tsdown": "^0.22.2",
|
|
"typescript": "^5.9.3"
|
|
}
|
|
}
|