LibreChat/packages/client/package.json
Marco Beretta 8a118c7cb3
⏱️ feat: Shared Time Picker for Schedule Times (#15122)
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.
2026-08-23 22:47:33 +00:00

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"
}
}