@lessly/ui 3.0.0 → 4.0.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/dist/{chunk-CEXND5YW.js → chunk-DYHP7W3X.js} +175 -28
- package/dist/index.d.ts +334 -51
- package/dist/index.js +837 -670
- package/dist/router.d.ts +27 -17
- package/dist/router.js +69 -94
- package/dist/styles-federated.css +45 -9
- package/dist/styles.css +45 -9
- package/package.json +14 -13
|
@@ -71,10 +71,12 @@ var buttonVariants = cva(
|
|
|
71
71
|
// colour would reach the element beside the variant's and stylesheet order would pick.
|
|
72
72
|
variant: {
|
|
73
73
|
default: "bg-blue-400 text-text-on-brand focus-visible:ring-border-focus hover:bg-blue-350",
|
|
74
|
-
/** The
|
|
75
|
-
*
|
|
74
|
+
/** The wash carries the danger at rest, on the neutral frame every object button wears — so
|
|
75
|
+
* a pair still ranks by weight rather than by colour, and the signal survives a touch
|
|
76
|
+
* device that never hovers. The label rests neutral because a variant differs by frame and
|
|
77
|
+
* fill and never by text colour (#449). Hover reddens the frame and the label; keyboard
|
|
76
78
|
* focus reddens the ring alone. */
|
|
77
|
-
destructive: "border border-border-
|
|
79
|
+
destructive: "border border-border-default bg-bg-danger-subtle text-text-primary focus-visible:ring-border-danger hover:border-border-danger hover:text-text-danger",
|
|
78
80
|
/** The borderless form of `destructive`, for an icon-only revoke repeated down a list — a row
|
|
79
81
|
* of framed ✕ buttons would shout. */
|
|
80
82
|
"destructive-ghost": "text-text-tertiary focus-visible:ring-border-focus hover:bg-bg-danger-subtle hover:text-text-danger",
|
|
@@ -83,7 +85,7 @@ var buttonVariants = cva(
|
|
|
83
85
|
* `StepUpChallenge destructive` one. Use `destructive` for any trigger that sits on a page. */
|
|
84
86
|
"destructive-solid": "bg-bg-danger text-text-on-danger focus-visible:ring-border-focus hover:bg-bg-danger-a90",
|
|
85
87
|
outline: "border border-border-default bg-transparent text-text-primary focus-visible:ring-border-focus hover:bg-bg-secondary",
|
|
86
|
-
secondary: "bg-bg-secondary text-text-primary focus-visible:ring-border-focus hover:bg-bg-secondary-a80",
|
|
88
|
+
secondary: "border border-border-default bg-bg-secondary text-text-primary focus-visible:ring-border-focus hover:bg-bg-secondary-a80",
|
|
87
89
|
/** The frameless console tone, and the add affordance — `variant="ghost" size="xs"` with a
|
|
88
90
|
* leading `+`. It rests at `text-text-primary` because a button's variant differs by frame
|
|
89
91
|
* and fill, never by text colour; `destructive-ghost` keeps its quieter rest on purpose. */
|
|
@@ -290,7 +292,7 @@ var SheetContent = React3.forwardRef(({ side = "right", className, children, ...
|
|
|
290
292
|
...props,
|
|
291
293
|
children: [
|
|
292
294
|
children,
|
|
293
|
-
/* @__PURE__ */ jsxs2(SheetPrimitive.Close, { className: "absolute right-4 top-4 rounded-sm text-text-tertiary opacity-70 transition-opacity duration-fast hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-border-focus disabled:pointer-events-none", children: [
|
|
295
|
+
/* @__PURE__ */ jsxs2(SheetPrimitive.Close, { className: "absolute right-4 top-4 cursor-pointer rounded-sm text-text-tertiary opacity-70 transition-opacity duration-fast hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-border-focus disabled:pointer-events-none", children: [
|
|
294
296
|
/* @__PURE__ */ jsx3(X, { className: "h-4 w-4" }),
|
|
295
297
|
/* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Close" })
|
|
296
298
|
] })
|
|
@@ -334,6 +336,66 @@ var SheetDescription = React3.forwardRef(({ className, ...props }, ref) => /* @_
|
|
|
334
336
|
));
|
|
335
337
|
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
336
338
|
|
|
339
|
+
// src/components/entity-row.tsx
|
|
340
|
+
import * as React4 from "react";
|
|
341
|
+
import { Slot as Slot2 } from "@radix-ui/react-slot";
|
|
342
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
343
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
344
|
+
var rowClass = "flex w-full items-center gap-3 px-4 py-2.5 text-left";
|
|
345
|
+
var plateClass = "relative isolate after:pointer-events-none after:absolute after:inset-x-1.5 after:inset-y-1 after:-z-10 after:rounded-lg hover:after:bg-[var(--hov-bg)] disabled:hover:after:bg-transparent focus-visible:outline-none focus-visible:after:ring-2 focus-visible:after:ring-inset focus-visible:after:ring-border-focus";
|
|
346
|
+
var stackClass = "flex-col items-stretch gap-1";
|
|
347
|
+
var caretMotion = {
|
|
348
|
+
transitionDuration: "var(--motion-duration-normal)",
|
|
349
|
+
transitionTimingFunction: "var(--motion-easing-standard)"
|
|
350
|
+
};
|
|
351
|
+
var EntityRow = React4.forwardRef(function EntityRow2({ mark, title, badge, sub, meta, summary, opens = "page", expanded, asChild = false, className, children, ...props }, ref) {
|
|
352
|
+
if (process.env.NODE_ENV !== "production" && opens === "disclosure" && expanded === void 0) {
|
|
353
|
+
console.warn(
|
|
354
|
+
'[EntityRow] `opens="disclosure"` needs `expanded`: it draws the caret AND sets `aria-expanded`, and without it the row renders a caret that never turns and states no state at all. Pass `expanded={open}`, or use `opens="page"` / `opens="modal"`.'
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
const line = /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
358
|
+
mark,
|
|
359
|
+
/* @__PURE__ */ jsxs3("span", { className: "min-w-0 flex-1", children: [
|
|
360
|
+
/* @__PURE__ */ jsxs3("span", { className: "flex min-h-5 items-center gap-2", children: [
|
|
361
|
+
/* @__PURE__ */ jsx4("span", { className: cn("truncate text-sm text-text-primary", opens !== "none" && "font-medium"), children: title }),
|
|
362
|
+
badge != null && /* @__PURE__ */ jsx4("span", { className: "flex h-5 shrink-0 items-center", children: badge })
|
|
363
|
+
] }),
|
|
364
|
+
sub != null && /* @__PURE__ */ jsx4("span", { className: "block truncate text-xs text-text-secondary", children: sub })
|
|
365
|
+
] }),
|
|
366
|
+
meta != null && /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-sm text-text-secondary", children: meta }),
|
|
367
|
+
opens !== "none" && /* @__PURE__ */ jsxs3("span", { className: "flex size-4 shrink-0 items-center justify-center", children: [
|
|
368
|
+
opens === "page" && /* @__PURE__ */ jsx4(ChevronRight, { className: "size-4 text-text-tertiary", "aria-hidden": true }),
|
|
369
|
+
opens === "disclosure" && /* @__PURE__ */ jsx4(
|
|
370
|
+
ChevronDown,
|
|
371
|
+
{
|
|
372
|
+
className: cn(
|
|
373
|
+
"size-4 shrink-0 text-text-tertiary transition-transform",
|
|
374
|
+
expanded ? "rotate-180" : "rotate-0"
|
|
375
|
+
),
|
|
376
|
+
style: caretMotion,
|
|
377
|
+
"aria-hidden": true
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
] })
|
|
381
|
+
] });
|
|
382
|
+
const content = summary == null ? line : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
383
|
+
/* @__PURE__ */ jsx4("span", { className: "flex w-full items-center gap-3", children: line }),
|
|
384
|
+
/* @__PURE__ */ jsx4("span", { className: "block w-full text-xs text-text-secondary", children: summary })
|
|
385
|
+
] });
|
|
386
|
+
const classes = cn(rowClass, opens !== "none" && ["cursor-pointer", plateClass], summary != null && stackClass, className);
|
|
387
|
+
const stateProps = opens === "disclosure" ? { "aria-expanded": expanded } : void 0;
|
|
388
|
+
if (opens === "none") {
|
|
389
|
+
return /* @__PURE__ */ jsx4("div", { ...props, ref, className: classes, children: content });
|
|
390
|
+
}
|
|
391
|
+
if (asChild) {
|
|
392
|
+
const child = React4.Children.only(children);
|
|
393
|
+
return /* @__PURE__ */ jsx4(Slot2, { ...props, ref, className: classes, ...stateProps, children: React4.cloneElement(child, stateProps, content) });
|
|
394
|
+
}
|
|
395
|
+
return /* @__PURE__ */ jsx4("button", { ...props, ref, type: "button", className: classes, ...stateProps, children: content });
|
|
396
|
+
});
|
|
397
|
+
EntityRow.displayName = "EntityRow";
|
|
398
|
+
|
|
337
399
|
// src/hooks/use-mobile.ts
|
|
338
400
|
import { useEffect, useState as useState2 } from "react";
|
|
339
401
|
var MD_BREAKPOINT = 768;
|
|
@@ -376,10 +438,11 @@ function useSidebar(options = {}) {
|
|
|
376
438
|
}
|
|
377
439
|
|
|
378
440
|
// src/components/nav-row.tsx
|
|
379
|
-
import * as
|
|
380
|
-
import { Slot as
|
|
381
|
-
import {
|
|
382
|
-
|
|
441
|
+
import * as React5 from "react";
|
|
442
|
+
import { Slot as Slot3 } from "@radix-ui/react-slot";
|
|
443
|
+
import { ChevronDown as ChevronDown2, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
444
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
445
|
+
var base = "flex w-full cursor-pointer items-center text-left text-sm transition-colors duration-fast focus-visible:outline-none";
|
|
383
446
|
var ring = "focus-visible:ring-2 focus-visible:ring-border-focus";
|
|
384
447
|
var plate = "relative isolate after:pointer-events-none after:absolute after:inset-x-1.5 after:inset-y-1 after:-z-10 after:rounded-lg";
|
|
385
448
|
var shape = {
|
|
@@ -390,23 +453,43 @@ var shape = {
|
|
|
390
453
|
var state = {
|
|
391
454
|
rail: {
|
|
392
455
|
idle: "font-medium text-text-secondary hover:bg-[var(--hov-bg)] hover:text-text-primary",
|
|
393
|
-
active: "bg-bg
|
|
456
|
+
active: "bg-[var(--current-bg)] font-semibold text-text-primary hover:bg-[var(--hov-current)]"
|
|
394
457
|
},
|
|
395
458
|
menu: {
|
|
396
459
|
idle: "font-medium text-text-secondary hover:bg-[var(--menu-hov)]",
|
|
397
|
-
active: "
|
|
460
|
+
active: "ring-1 ring-inset ring-border-strong font-semibold text-text-primary hover:bg-[var(--menu-hov)]"
|
|
398
461
|
},
|
|
399
462
|
// A settings line reads as a label, not as navigation, so it idles at the body weight the rest of
|
|
400
463
|
// the card is set in — and never marks itself current, because it isn't.
|
|
401
464
|
card: {
|
|
402
|
-
idle: "text-text-primary hover:after:bg-bg
|
|
403
|
-
active: "text-text-primary hover:after:bg-bg
|
|
465
|
+
idle: "text-text-primary hover:after:bg-[var(--hov-bg)]",
|
|
466
|
+
active: "text-text-primary hover:after:bg-[var(--hov-bg)]"
|
|
404
467
|
}
|
|
405
468
|
};
|
|
406
|
-
|
|
469
|
+
function Mark({ mark, open }) {
|
|
470
|
+
return /* @__PURE__ */ jsx5(
|
|
471
|
+
"span",
|
|
472
|
+
{
|
|
473
|
+
className: cn(
|
|
474
|
+
"flex size-5 items-center justify-center",
|
|
475
|
+
mark === "drill" ? "rounded-md transition-colors duration-fast group-hover/nav-row:bg-[color-mix(in_srgb,var(--text-primary)_10%,transparent)]" : "text-text-tertiary"
|
|
476
|
+
),
|
|
477
|
+
children: mark === "drill" ? /* @__PURE__ */ jsx5(ChevronRight2, { className: "size-4", "aria-hidden": "true" }) : /* @__PURE__ */ jsx5(
|
|
478
|
+
ChevronDown2,
|
|
479
|
+
{
|
|
480
|
+
className: "size-4",
|
|
481
|
+
style: { ...caretMotion, transitionProperty: "transform", transform: open ? "rotate(180deg)" : "rotate(0deg)" },
|
|
482
|
+
"aria-hidden": "true"
|
|
483
|
+
}
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
var NavRow = React5.forwardRef(function NavRow2({ icon, label, sub, active = false, variant, trailing, mark, markOpen, mutedTrailing = false, hideLabel = false, asChild = false, className, children, ...props }, ref) {
|
|
407
489
|
const card = variant === "card";
|
|
408
|
-
const
|
|
409
|
-
|
|
490
|
+
const adornment = mark ? !hideLabel && /* @__PURE__ */ jsx5(Mark, { mark, open: markOpen }) : trailing;
|
|
491
|
+
const content = /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
492
|
+
Boolean(icon) && /* @__PURE__ */ jsx5(
|
|
410
493
|
"span",
|
|
411
494
|
{
|
|
412
495
|
className: cn(
|
|
@@ -417,31 +500,92 @@ var NavRow = React4.forwardRef(function NavRow2({ icon, label, sub, active = fal
|
|
|
417
500
|
children: icon
|
|
418
501
|
}
|
|
419
502
|
),
|
|
420
|
-
!hideLabel && (card ? /* @__PURE__ */
|
|
421
|
-
/* @__PURE__ */
|
|
422
|
-
Boolean(sub) && /* @__PURE__ */
|
|
423
|
-
] }) : /* @__PURE__ */
|
|
424
|
-
Boolean(
|
|
503
|
+
!hideLabel && (card ? /* @__PURE__ */ jsxs4("span", { "data-slot": "nav-row-label", className: "min-w-0 flex-1", children: [
|
|
504
|
+
/* @__PURE__ */ jsx5("span", { className: "block truncate", children: label }),
|
|
505
|
+
Boolean(sub) && /* @__PURE__ */ jsx5("span", { className: "block truncate text-xs text-text-secondary", children: sub })
|
|
506
|
+
] }) : /* @__PURE__ */ jsx5("span", { "data-slot": "nav-row-label", className: "min-w-0 flex-1 truncate", children: label })),
|
|
507
|
+
Boolean(adornment) && /* @__PURE__ */ jsx5(
|
|
425
508
|
"span",
|
|
426
509
|
{
|
|
510
|
+
"data-slot": "nav-row-trailing",
|
|
427
511
|
className: cn(
|
|
428
512
|
"flex shrink-0 items-center",
|
|
429
513
|
mutedTrailing ? "text-text-tertiary" : card && "text-text-secondary"
|
|
430
514
|
),
|
|
431
|
-
children:
|
|
515
|
+
children: adornment
|
|
432
516
|
}
|
|
433
517
|
),
|
|
434
|
-
card && /* @__PURE__ */
|
|
518
|
+
card && /* @__PURE__ */ jsx5("span", { className: "size-4 shrink-0", "aria-hidden": "true" })
|
|
435
519
|
] });
|
|
436
|
-
const classes = cn(
|
|
520
|
+
const classes = cn(
|
|
521
|
+
base,
|
|
522
|
+
shape[variant],
|
|
523
|
+
state[variant][active ? "active" : "idle"],
|
|
524
|
+
// The drill mark's own plate lights on the row, so the row is what the plate hangs off.
|
|
525
|
+
mark === "drill" && "group/nav-row",
|
|
526
|
+
className
|
|
527
|
+
);
|
|
528
|
+
const expanded = mark === "disclosure" ? markOpen : void 0;
|
|
437
529
|
if (asChild) {
|
|
438
|
-
const child =
|
|
439
|
-
return /* @__PURE__ */
|
|
530
|
+
const child = React5.Children.only(children);
|
|
531
|
+
return /* @__PURE__ */ jsx5(Slot3, { ref, className: classes, "aria-label": hideLabel ? label : void 0, "aria-expanded": expanded, ...props, children: React5.cloneElement(child, void 0, content) });
|
|
440
532
|
}
|
|
441
|
-
return /* @__PURE__ */
|
|
533
|
+
return /* @__PURE__ */ jsx5("button", { ref, type: "button", className: classes, "aria-label": hideLabel ? label : void 0, "aria-expanded": expanded, ...props, children: content });
|
|
442
534
|
});
|
|
443
535
|
NavRow.displayName = "NavRow";
|
|
444
536
|
|
|
537
|
+
// src/components/rail-toggle.tsx
|
|
538
|
+
import * as React6 from "react";
|
|
539
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
540
|
+
var RAIL_COLUMN_BOX = "flex size-10 shrink-0 items-center justify-center [&>*]:shrink-0";
|
|
541
|
+
var BAR_TRAVEL = 6;
|
|
542
|
+
function RailMark({ collapsed, className }) {
|
|
543
|
+
return /* @__PURE__ */ jsxs5(
|
|
544
|
+
"svg",
|
|
545
|
+
{
|
|
546
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
547
|
+
viewBox: "0 0 24 24",
|
|
548
|
+
fill: "none",
|
|
549
|
+
stroke: "currentColor",
|
|
550
|
+
strokeWidth: 2,
|
|
551
|
+
strokeLinecap: "round",
|
|
552
|
+
strokeLinejoin: "round",
|
|
553
|
+
className: cn("size-4", className),
|
|
554
|
+
"aria-hidden": "true",
|
|
555
|
+
children: [
|
|
556
|
+
/* @__PURE__ */ jsx6("rect", { "data-slot": "rail-mark-frame", x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
557
|
+
/* @__PURE__ */ jsx6(
|
|
558
|
+
"path",
|
|
559
|
+
{
|
|
560
|
+
"data-slot": "rail-mark-bar",
|
|
561
|
+
className: "motion-rail-collapse",
|
|
562
|
+
d: "M9 3v18",
|
|
563
|
+
style: { transform: `translateX(${collapsed ? BAR_TRAVEL : 0}px)` }
|
|
564
|
+
}
|
|
565
|
+
)
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
var RailToggle = React6.forwardRef(function RailToggle2({ collapsed, className, "aria-label": ariaLabel, ...rest }, ref) {
|
|
571
|
+
return /* @__PURE__ */ jsx6(
|
|
572
|
+
"button",
|
|
573
|
+
{
|
|
574
|
+
ref,
|
|
575
|
+
type: "button",
|
|
576
|
+
"aria-label": ariaLabel ?? (collapsed ? "Expand sidebar" : "Collapse sidebar"),
|
|
577
|
+
"aria-expanded": !collapsed,
|
|
578
|
+
className: cn(
|
|
579
|
+
RAIL_COLUMN_BOX,
|
|
580
|
+
"cursor-pointer rounded-md text-text-secondary transition-colors duration-fast hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
581
|
+
className
|
|
582
|
+
),
|
|
583
|
+
...rest,
|
|
584
|
+
children: /* @__PURE__ */ jsx6(RailMark, { collapsed })
|
|
585
|
+
}
|
|
586
|
+
);
|
|
587
|
+
});
|
|
588
|
+
|
|
445
589
|
export {
|
|
446
590
|
cn,
|
|
447
591
|
buttonVariants,
|
|
@@ -460,7 +604,10 @@ export {
|
|
|
460
604
|
SheetFooter,
|
|
461
605
|
SheetTitle,
|
|
462
606
|
SheetDescription,
|
|
607
|
+
EntityRow,
|
|
463
608
|
useIsMobile,
|
|
464
609
|
useSidebar,
|
|
465
|
-
NavRow
|
|
610
|
+
NavRow,
|
|
611
|
+
RAIL_COLUMN_BOX,
|
|
612
|
+
RailToggle
|
|
466
613
|
};
|