twico-ui 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.cjs +1084 -683
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +384 -146
- package/dist/index.d.ts +384 -146
- package/dist/index.mjs +1083 -684
- package/dist/index.mjs.map +1 -1
- package/llms.txt +32 -9
- package/package.json +3 -1
- package/styles/twico-ui.css +15 -5
package/llms.txt
CHANGED
|
@@ -291,6 +291,8 @@ Props:
|
|
|
291
291
|
- `children` — `React.ReactNode` — Main content; fills the remaining space and scrolls independently of the fixed sidebar and header.
|
|
292
292
|
- `height` — `string | number` · default `"100dvh"` — Overall shell height; pass a fixed value to embed the shell inside a smaller region (e.g. a demo).
|
|
293
293
|
- `padded` — `boolean` · default `true` — Pads the scrollable content region with the standard page padding; set false for edge-to-edge content.
|
|
294
|
+
- `sidebarOpen` — `boolean` — Open state of the sidebar's off-canvas drawer on mobile; providing this (or onSidebarOpenChange) makes the shell forward overlay/open/onOpenChange to the sidebar element.
|
|
295
|
+
- `onSidebarOpenChange` — `(open: boolean) => void` — Called when the sidebar drawer requests open or close; wire a Navbar's onMenuClick to () => onSidebarOpenChange(true) for the mobile menu button.
|
|
294
296
|
|
|
295
297
|
```jsx
|
|
296
298
|
import { AppShell, Sidebar, Button } from "twico-ui";
|
|
@@ -1774,6 +1776,11 @@ Props:
|
|
|
1774
1776
|
- `defaultCollapsed` — `boolean` · default `false` — Initial collapsed state for uncontrolled usage, defaulting to false so the sidebar starts fully expanded.
|
|
1775
1777
|
- `collapsible` — `boolean` · default `true` — Shows the collapse toggle button when true (the default), allowing users to switch to the icon-only rail.
|
|
1776
1778
|
- `onCollapsedChange` — `(collapsed: boolean) => void` — Fires with the new boolean state whenever the collapse toggle is activated, useful for persisting the preference.
|
|
1779
|
+
- `overlay` — `boolean` · default `false` — Renders the sidebar as an off-canvas drawer instead of an in-flow rail: a fixed slide-over panel behind a dismissable backdrop, portaled to the body, with a focus trap, Escape-to-close, and scroll lock.
|
|
1780
|
+
- `open` — `boolean` — Controlled open state of the overlay drawer (only meaningful when overlay is set); the parent owns visibility.
|
|
1781
|
+
- `defaultOpen` — `boolean` · default `false` — Initial open state of the overlay drawer for uncontrolled usage, defaulting to closed.
|
|
1782
|
+
- `onOpenChange` — `(open: boolean) => void` — Fires when the overlay drawer requests open or close (backdrop click or Escape); wire it to your open state.
|
|
1783
|
+
- `navLabel` — `string` · default `"Main"` — Accessible name for the inner nav landmark and the overlay dialog, so assistive tech can distinguish multiple navigations.
|
|
1777
1784
|
|
|
1778
1785
|
```jsx
|
|
1779
1786
|
import { Sidebar } from "twico-ui";
|
|
@@ -2279,7 +2286,7 @@ function Page() {
|
|
|
2279
2286
|
}
|
|
2280
2287
|
```
|
|
2281
2288
|
|
|
2282
|
-
## Hooks (
|
|
2289
|
+
## Hooks (25)
|
|
2283
2290
|
|
|
2284
2291
|
### useIsomorphicLayoutEffect
|
|
2285
2292
|
|
|
@@ -2323,18 +2330,18 @@ export function useDisclosure(initial?: boolean): { open: boolean; onOpen: () =>
|
|
|
2323
2330
|
|
|
2324
2331
|
### useControllableState
|
|
2325
2332
|
|
|
2326
|
-
Controlled/uncontrolled state — the pattern every form component needs.
|
|
2333
|
+
Controlled/uncontrolled state — the pattern every form component needs. Returns `[value, setValue, isControlled]`; the third element reports whether a `value` prop is currently driving the state. In development it warns once if a component switches between controlled and uncontrolled.
|
|
2327
2334
|
|
|
2328
2335
|
```ts
|
|
2329
|
-
export function useControllableState<T>(options?: { value?: T; defaultValue?: T; onChange?: (value: T) => void; }): [T, (next: T | ((prev: T) => T)) => void];
|
|
2336
|
+
export function useControllableState<T>(options?: { value?: T; defaultValue?: T; onChange?: (value: T) => void; }): [T, (next: T | ((prev: T) => T)) => void, boolean];
|
|
2330
2337
|
```
|
|
2331
2338
|
|
|
2332
2339
|
### useMediaQuery
|
|
2333
2340
|
|
|
2334
|
-
Reactively match a media query
|
|
2341
|
+
Reactively match a media query. Returns `defaultValue` on the server and the first client render, then syncs after mount — so hydration never mismatches.
|
|
2335
2342
|
|
|
2336
2343
|
```ts
|
|
2337
|
-
export function useMediaQuery(query: string): boolean;
|
|
2344
|
+
export function useMediaQuery(query: string, options?: UseMediaQueryOptions): boolean;
|
|
2338
2345
|
```
|
|
2339
2346
|
|
|
2340
2347
|
### usePrefersReducedMotion
|
|
@@ -2358,7 +2365,7 @@ export function useColorScheme(options?: UseColorSchemeOptions): { theme: "light
|
|
|
2358
2365
|
Attach an event listener (window by default, or a ref/element) with cleanup.
|
|
2359
2366
|
|
|
2360
2367
|
```ts
|
|
2361
|
-
export function useEventListener( eventName: string, handler: (event: any) => void, element?: React.RefObject<any> | EventTarget | null, options?: boolean | AddEventListenerOptions ): void;
|
|
2368
|
+
export function useEventListener( eventName: string, handler: (event: any) => void, element?: React.RefObject<any | null> | EventTarget | null, options?: boolean | AddEventListenerOptions ): void;
|
|
2362
2369
|
```
|
|
2363
2370
|
|
|
2364
2371
|
### useClickOutside
|
|
@@ -2366,7 +2373,7 @@ export function useEventListener( eventName: string, handler: (event: any) => vo
|
|
|
2366
2373
|
Call `handler` when a pointer/touch event lands outside `ref`.
|
|
2367
2374
|
|
|
2368
2375
|
```ts
|
|
2369
|
-
export function useClickOutside<T extends HTMLElement = HTMLElement>( ref: React.RefObject<T>, handler: (event: Event) => void, events?: string[] ): void;
|
|
2376
|
+
export function useClickOutside<T extends HTMLElement = HTMLElement>( ref: React.RefObject<T | null>, handler: (event: Event) => void, events?: string[] ): void;
|
|
2370
2377
|
```
|
|
2371
2378
|
|
|
2372
2379
|
### useKeyPress
|
|
@@ -2438,7 +2445,7 @@ export function useWindowSize(): { width: number; height: number };
|
|
|
2438
2445
|
`true` while the pointer is over the element referenced by `ref`.
|
|
2439
2446
|
|
|
2440
2447
|
```ts
|
|
2441
|
-
export function useHover<T extends HTMLElement = HTMLElement>(ref: React.RefObject<T>): boolean;
|
|
2448
|
+
export function useHover<T extends HTMLElement = HTMLElement>(ref: React.RefObject<T | null>): boolean;
|
|
2442
2449
|
```
|
|
2443
2450
|
|
|
2444
2451
|
### useIntersectionObserver
|
|
@@ -2446,7 +2453,7 @@ export function useHover<T extends HTMLElement = HTMLElement>(ref: React.RefObje
|
|
|
2446
2453
|
The latest IntersectionObserver entry for the element referenced by `ref`.
|
|
2447
2454
|
|
|
2448
2455
|
```ts
|
|
2449
|
-
export function useIntersectionObserver<T extends HTMLElement = HTMLElement>( ref: React.RefObject<T>, options?: IntersectionObserverInit ): IntersectionObserverEntry | null;
|
|
2456
|
+
export function useIntersectionObserver<T extends HTMLElement = HTMLElement>( ref: React.RefObject<T | null>, options?: IntersectionObserverInit ): IntersectionObserverEntry | null;
|
|
2450
2457
|
```
|
|
2451
2458
|
|
|
2452
2459
|
### useScrollLock
|
|
@@ -2465,6 +2472,22 @@ A stable, SSR-safe unique id (optionally prefixed).
|
|
|
2465
2472
|
export function useId(prefix?: string): string;
|
|
2466
2473
|
```
|
|
2467
2474
|
|
|
2475
|
+
### useFocusTrap
|
|
2476
|
+
|
|
2477
|
+
Trap focus inside the modal region referenced by `ref`. While `active`, focus moves inside on activate, Tab/Shift+Tab cycle within it, and (by default) focus is restored to the previously-focused element on deactivate. Escape is NOT handled — that stays with the component. SSR-safe.
|
|
2478
|
+
|
|
2479
|
+
```ts
|
|
2480
|
+
export function useFocusTrap<T extends HTMLElement = HTMLElement>( ref: React.RefObject<T | null>, active?: boolean, options?: UseFocusTrapOptions ): void;
|
|
2481
|
+
```
|
|
2482
|
+
|
|
2483
|
+
### usePortal
|
|
2484
|
+
|
|
2485
|
+
Returns a stable `render(node)` that portals `node` to `document.body`, or `null` on the server (no document). Centralizes the overlay portal pattern.
|
|
2486
|
+
|
|
2487
|
+
```ts
|
|
2488
|
+
export function usePortal(): (node: React.ReactNode) => React.ReactPortal | React.ReactNode | null;
|
|
2489
|
+
```
|
|
2490
|
+
|
|
2468
2491
|
---
|
|
2469
2492
|
|
|
2470
2493
|
_Generated by `scripts/gen-llms.mjs`. Do not edit by hand — run `npm run gen:llms`. Source of truth: the component `.d.ts` files and `hooks/index.d.ts`._
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twico-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Twico UI — a free, modern, themeable React + Tailwind-friendly component library. 61 components with dark mode, motion, and accessibility built in.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Twico UI",
|
|
@@ -82,6 +82,8 @@
|
|
|
82
82
|
"gen:llms:check": "node scripts/gen-llms.mjs --check",
|
|
83
83
|
"typecheck": "tsc --noEmit",
|
|
84
84
|
"check:exports": "attw --pack . --profile node16 --exclude-entrypoints styles.css",
|
|
85
|
+
"gen:ds-bundle": "node scripts/gen-ds-bundle.mjs",
|
|
86
|
+
"check:ds-bundle": "node scripts/check-ds-bundle.mjs",
|
|
85
87
|
"test": "vitest",
|
|
86
88
|
"test:run": "vitest run",
|
|
87
89
|
"size": "size-limit",
|
package/styles/twico-ui.css
CHANGED
|
@@ -169,8 +169,9 @@
|
|
|
169
169
|
--color-primary-subtle-fg: var(--brand-700);
|
|
170
170
|
--color-primary-border: var(--brand-200);
|
|
171
171
|
|
|
172
|
-
/* Focus ring
|
|
173
|
-
|
|
172
|
+
/* Focus ring — solid brand so the 3px ring clears WCAG 2.4.11 / 1.4.11 (3:1)
|
|
173
|
+
on light surfaces (a translucent indigo alpha-composited to only ~1.8:1). */
|
|
174
|
+
--color-ring: var(--brand-500);
|
|
174
175
|
|
|
175
176
|
/* Success */
|
|
176
177
|
--color-success: var(--emerald-600);
|
|
@@ -180,7 +181,7 @@
|
|
|
180
181
|
|
|
181
182
|
/* Warning */
|
|
182
183
|
--color-warning: var(--amber-500);
|
|
183
|
-
--color-warning-fg:
|
|
184
|
+
--color-warning-fg: var(--amber-950); /* dark ink on amber-500 = 6.97:1 (white was 2.15:1) */
|
|
184
185
|
--color-warning-subtle: var(--amber-50);
|
|
185
186
|
--color-warning-subtle-fg: var(--amber-600);
|
|
186
187
|
|
|
@@ -193,7 +194,7 @@
|
|
|
193
194
|
|
|
194
195
|
/* Info */
|
|
195
196
|
--color-info: var(--sky-500);
|
|
196
|
-
--color-info-fg:
|
|
197
|
+
--color-info-fg: var(--sky-950); /* dark ink on sky-500 (white was 2.77:1) */
|
|
197
198
|
--color-info-subtle: var(--sky-50);
|
|
198
199
|
--color-info-subtle-fg: var(--sky-600);
|
|
199
200
|
}
|
|
@@ -229,7 +230,7 @@
|
|
|
229
230
|
--color-primary-subtle-fg: var(--brand-300);
|
|
230
231
|
--color-primary-border: rgb(99 102 241 / 0.35);
|
|
231
232
|
|
|
232
|
-
--color-ring:
|
|
233
|
+
--color-ring: var(--brand-400); /* solid brand-400 ≈ 5.7:1 on slate-900 (translucent was ~2.7:1) */
|
|
233
234
|
|
|
234
235
|
--color-success: var(--emerald-500);
|
|
235
236
|
--color-success-fg: #052e1d;
|
|
@@ -564,6 +565,15 @@ textarea:focus-visible,
|
|
|
564
565
|
select:focus-visible {
|
|
565
566
|
box-shadow: none;
|
|
566
567
|
}
|
|
568
|
+
/* Windows High Contrast / forced-colors strips author box-shadows, which would
|
|
569
|
+
erase the box-shadow focus ring entirely. Repaint a real outline in the user's
|
|
570
|
+
system palette (CanvasText) — the designed ring is untouched in normal render. */
|
|
571
|
+
@media (forced-colors: active) {
|
|
572
|
+
:focus-visible {
|
|
573
|
+
outline: 2px solid CanvasText;
|
|
574
|
+
outline-offset: 2px;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
567
577
|
|
|
568
578
|
::selection {
|
|
569
579
|
background: var(--color-primary-subtle);
|