@assure-one/design-system 0.16.0 → 0.17.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/index.d.ts CHANGED
@@ -108,7 +108,7 @@ declare const Badge: React$1.ForwardRefExoticComponent<BadgeProps & React$1.RefA
108
108
 
109
109
  /**
110
110
  * Blockquote — semantic quote with optional attribution. Uses `font-display`
111
- * (Geist) at a comfortable reading scale; smart quotes are wrapped automatically.
111
+ * (Inter) at a comfortable reading scale; smart quotes are wrapped automatically.
112
112
  */
113
113
  interface BlockquoteProps extends React.BlockquoteHTMLAttributes<HTMLQuoteElement> {
114
114
  author?: string;
@@ -227,6 +227,8 @@ interface CheckboxProps extends Omit<React$1.ComponentPropsWithoutRef<typeof Che
227
227
  defaultChecked?: boolean | "indeterminate";
228
228
  /** Convenience: render with indeterminate state. Mirrors legacy prop. */
229
229
  indeterminate?: boolean;
230
+ /** Box shape. Defaults to "square". */
231
+ shape?: "square" | "circle";
230
232
  }
231
233
  declare const Checkbox: React$1.ForwardRefExoticComponent<CheckboxProps & React$1.RefAttributes<HTMLButtonElement>>;
232
234
 
@@ -508,7 +510,7 @@ declare const DropdownMenuShortcut: {
508
510
  };
509
511
 
510
512
  /**
511
- * EmptyState — display headline (Geist), fg-3 description, neutral icon halo on bg-2.
513
+ * EmptyState — display headline (Inter), fg-3 description, neutral icon halo on bg-2.
512
514
  *
513
515
  * Public API preserved: `icon`, `title`, `description`, `action`.
514
516
  */
@@ -847,7 +849,7 @@ declare const LoadingRows: React$1.ForwardRefExoticComponent<LoadingRowsProps &
847
849
 
848
850
  /**
849
851
  * Logo — Assure suite wordmark. Renders "Assure" in `fg` plus an optional
850
- * product suffix in `pro-fg` (e.g., "Pro", "Tax"), set in Geist (font-display).
852
+ * product suffix in `pro-fg` (e.g., "Pro", "Tax"), set in Inter (font-display).
851
853
  *
852
854
  * The product suffix is configurable so the same component serves every
853
855
  * Assure product. The default preserves the original "Assure Pro" output —
@@ -1161,15 +1163,23 @@ interface SearchSelectProps {
1161
1163
  */
1162
1164
  onCreateNew?: () => void;
1163
1165
  createNewLabel?: string;
1166
+ /**
1167
+ * How the collapsed single-value display renders the picked option's
1168
+ * `description`. "inline" (default) appends it as muted "· text" after the
1169
+ * label — the existing behaviour. "pill" renders it as a discrete rounded
1170
+ * badge after the label, so dense metadata (e.g. "1040 · 2025", "todo")
1171
+ * reads as a tag instead of running into the label. Single-mode only.
1172
+ */
1173
+ descriptionVariant?: "inline" | "pill";
1164
1174
  }
1165
- declare function SearchSelect({ options, selected: selectedProp, onSelect: onSelectProp, onRemove: onRemoveProp, value, onValueChange, onCreate, placeholder, className, disabled, groupFilter, pinnedGroups, closeOnSelect: closeOnSelectProp, showGroupCounts, onCreateNew, createNewLabel, }: SearchSelectProps): react_jsx_runtime.JSX.Element;
1175
+ declare function SearchSelect({ options, selected: selectedProp, onSelect: onSelectProp, onRemove: onRemoveProp, value, onValueChange, onCreate, placeholder, className, disabled, groupFilter, pinnedGroups, closeOnSelect: closeOnSelectProp, showGroupCounts, onCreateNew, createNewLabel, descriptionVariant, }: SearchSelectProps): react_jsx_runtime.JSX.Element;
1166
1176
  declare namespace SearchSelect {
1167
1177
  var displayName: string;
1168
1178
  }
1169
1179
 
1170
1180
  /**
1171
1181
  * SectionHeader — title + description block for marketing-style sections.
1172
- * Uses Geist (`font-display`) with the spec's `-0.022em` letterspacing.
1182
+ * Uses Inter (`font-display`) with the spec's `-0.022em` letterspacing.
1173
1183
  */
1174
1184
  interface SectionHeaderProps {
1175
1185
  title: string;
@@ -1409,7 +1419,7 @@ declare const StarRating: React$1.ForwardRefExoticComponent<StarRatingProps & Re
1409
1419
 
1410
1420
  /**
1411
1421
  * Stat — paired numeric display + caption (the StatNum primitive).
1412
- * Numerals are set in `font-display` (Geist) at a fluid clamp size with
1422
+ * Numerals are set in `font-display` (Inter) at a fluid clamp size with
1413
1423
  * `font-variant-numeric: tabular-nums` for vertical alignment.
1414
1424
  */
1415
1425
  interface StatProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -1680,6 +1690,16 @@ interface SidebarProps extends React$1.HTMLAttributes<HTMLElement> {
1680
1690
  * `collapsible` alone is a no-op.
1681
1691
  */
1682
1692
  collapsible?: boolean;
1693
+ /**
1694
+ * Visual treatment.
1695
+ * - `"classic"` (default) — full-height column flush to the left
1696
+ * edge with a right rule. The legacy look; unchanged.
1697
+ * - `"floating"` — a detached, rounded card inset from the viewport
1698
+ * with a soft shadow (modern SaaS pattern). Nav rows get larger
1699
+ * hit areas and a pill active state. Exposed as `data-variant` so
1700
+ * descendant atoms restyle via `group-data-[variant=floating]`.
1701
+ */
1702
+ variant?: "classic" | "floating";
1683
1703
  }
1684
1704
  declare const Sidebar: React$1.ForwardRefExoticComponent<SidebarProps & React$1.RefAttributes<HTMLElement>>;
1685
1705
  interface SidebarTriggerProps extends React$1.ButtonHTMLAttributes<HTMLButtonElement> {
@@ -1946,7 +1966,7 @@ interface PageHeaderProps extends Omit<React.HTMLAttributes<HTMLElement>, "title
1946
1966
  declare const PageHeader: React$1.ForwardRefExoticComponent<PageHeaderProps & React$1.RefAttributes<HTMLElement>>;
1947
1967
  type PageHeaderSpecProps = React.HTMLAttributes<HTMLSpanElement>;
1948
1968
  /**
1949
- * PageHeaderSpec — small `.spec`-style span (Geist Mono w/ tnum/lnum/ss01).
1969
+ * PageHeaderSpec — small `.spec`-style span (Inter w/ tnum/lnum/ss01).
1950
1970
  * Used inside the `meta` slot for numeric facts ("4 due today",
1951
1971
  * "EIN ·· 12-3456789").
1952
1972
  */
@@ -2162,7 +2182,7 @@ declare const DataTableCell: React$1.ForwardRefExoticComponent<DataTableCellProp
2162
2182
  */
2163
2183
  declare const DataTableCellName: React$1.ForwardRefExoticComponent<DataTableCellProps & React$1.RefAttributes<HTMLTableCellElement>>;
2164
2184
  /**
2165
- * DataTableCellMono — currency / IDs / numerics. Geist Mono with
2185
+ * DataTableCellMono — currency / IDs / numerics. Inter with
2166
2186
  * tabular numerals and tight tracking.
2167
2187
  */
2168
2188
  declare const DataTableCellMono: React$1.ForwardRefExoticComponent<DataTableCellProps & React$1.RefAttributes<HTMLTableCellElement>>;
@@ -2617,7 +2637,18 @@ interface UseStopwatchReturn {
2617
2637
  reset: () => void;
2618
2638
  }
2619
2639
  declare function useStopwatch(): UseStopwatchReturn;
2620
- type TimeLoggerProps = React$1.HTMLAttributes<HTMLDivElement>;
2640
+ interface TimeLoggerProps extends React$1.HTMLAttributes<HTMLDivElement> {
2641
+ /**
2642
+ * Layout direction.
2643
+ * - `"vertical"` (default) — the stacked panel; rows separated by top
2644
+ * rules. For popovers and side panels.
2645
+ * - `"horizontal"` — a single compact bar; segments sit side by side,
2646
+ * separated by left rules. For an app top/bottom bar. Exposed as
2647
+ * `data-orientation` so segment atoms flip their divider via
2648
+ * `group-data-[orientation=horizontal]/timelogger`.
2649
+ */
2650
+ orientation?: "vertical" | "horizontal";
2651
+ }
2621
2652
  declare const TimeLogger: React$1.ForwardRefExoticComponent<TimeLoggerProps & React$1.RefAttributes<HTMLDivElement>>;
2622
2653
  interface TimeLoggerHeaderProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, "title"> {
2623
2654
  title?: React$1.ReactNode;
package/dist/index.js CHANGED
@@ -90,9 +90,9 @@ var colors = {
90
90
  };
91
91
  var typography = {
92
92
  family: {
93
- display: '"Geist", "Inter", -apple-system, system-ui, sans-serif',
93
+ display: '"Inter", -apple-system, system-ui, sans-serif',
94
94
  body: '"Inter", -apple-system, system-ui, sans-serif',
95
- mono: '"Geist Mono", "JetBrains Mono", ui-monospace, monospace'
95
+ mono: '"Inter", -apple-system, system-ui, sans-serif'
96
96
  },
97
97
  weight: {
98
98
  regular: 400,
@@ -230,11 +230,24 @@ var systemTokens = {
230
230
  dangerBg: "var(--color-danger-bg)",
231
231
  dangerLine: "var(--color-danger-line)"
232
232
  },
233
+ gradient: {
234
+ brand: "var(--gradient-brand)",
235
+ pro: "var(--gradient-pro)",
236
+ audit: "var(--gradient-audit)",
237
+ books: "var(--gradient-books)",
238
+ tax: "var(--gradient-tax)"
239
+ },
233
240
  shadow: {
234
241
  quiet: "var(--shadow-quiet)",
235
242
  card: "var(--shadow-card)",
236
243
  pop: "var(--shadow-pop)",
237
- focusRing: "var(--shadow-focus-ring)"
244
+ focusRing: "var(--shadow-focus-ring)",
245
+ xs: "var(--shadow-xs)",
246
+ sm: "var(--shadow-sm)",
247
+ md: "var(--shadow-md)",
248
+ lg: "var(--shadow-lg)",
249
+ xl: "var(--shadow-xl)",
250
+ "2xl": "var(--shadow-2xl)"
238
251
  },
239
252
  radius: {
240
253
  btn: "var(--radius-btn)",
@@ -2235,6 +2248,7 @@ var AccordionTrigger = React36.forwardRef(function AccordionTrigger2({ children,
2235
2248
  "transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
2236
2249
  "hover:text-fg-2",
2237
2250
  "focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none",
2251
+ "data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50 data-[disabled]:hover:text-fg",
2238
2252
  "[&[data-state=open]>svg]:rotate-180",
2239
2253
  className
2240
2254
  ),
@@ -3013,7 +3027,16 @@ var CardAction = forwardRef(
3013
3027
  }
3014
3028
  );
3015
3029
  CardAction.displayName = "CardAction";
3016
- var Checkbox = React36.forwardRef(function Checkbox2({ label, indeterminate, checked, defaultChecked, className, id: providedId, ...props }, ref) {
3030
+ var Checkbox = React36.forwardRef(function Checkbox2({
3031
+ label,
3032
+ indeterminate,
3033
+ checked,
3034
+ defaultChecked,
3035
+ shape = "square",
3036
+ className,
3037
+ id: providedId,
3038
+ ...props
3039
+ }, ref) {
3017
3040
  const generatedId = React36.useId();
3018
3041
  const id = providedId ?? generatedId;
3019
3042
  const resolvedChecked = indeterminate ? "indeterminate" : checked;
@@ -3026,18 +3049,19 @@ var Checkbox = React36.forwardRef(function Checkbox2({ label, indeterminate, che
3026
3049
  checked: resolvedChecked,
3027
3050
  defaultChecked,
3028
3051
  className: cn(
3029
- "peer border-rule-strong bg-surface text-fg-on-pro flex size-4 shrink-0 items-center justify-center rounded-[4px] border",
3052
+ "peer border-rule-strong bg-surface text-pro-fg flex size-4 shrink-0 items-center justify-center border",
3053
+ shape === "circle" ? "rounded-full" : "rounded-[4px]",
3030
3054
  "transition-[color,background-color,border-color,box-shadow] duration-[var(--duration-fast)]",
3031
3055
  "hover:border-fg-4",
3032
3056
  "focus-visible:border-accent focus-visible:[box-shadow:var(--shadow-focus-ring)] focus-visible:outline-none",
3033
- "data-[state=checked]:border-pro-fg data-[state=checked]:bg-pro-fg",
3034
- "data-[state=indeterminate]:border-pro-fg data-[state=indeterminate]:bg-pro-fg",
3057
+ "data-[state=checked]:border-pro-fg data-[state=checked]:bg-pro-bg",
3058
+ "data-[state=indeterminate]:border-pro-fg data-[state=indeterminate]:bg-pro-bg",
3035
3059
  "disabled:bg-bg-disabled disabled:border-rule disabled:text-fg-disabled disabled:cursor-not-allowed",
3036
3060
  "aria-[invalid=true]:border-danger-line",
3037
3061
  className
3038
3062
  ),
3039
3063
  ...props,
3040
- children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx(MinusIcon, { className: "size-3", strokeWidth: 3, "aria-hidden": "true" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3", strokeWidth: 3, "aria-hidden": "true" }) })
3064
+ children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center text-current", children: resolvedChecked === "indeterminate" ? /* @__PURE__ */ jsx(MinusIcon, { className: "size-3", strokeWidth: 3, "aria-hidden": "true" }) : shape === "circle" ? /* @__PURE__ */ jsx("span", { className: "size-1.5 rounded-full bg-current", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(CheckIcon, { className: "size-3", strokeWidth: 3, "aria-hidden": "true" }) })
3041
3065
  }
3042
3066
  ),
3043
3067
  label && /* @__PURE__ */ jsx(
@@ -6062,7 +6086,8 @@ function SearchSelect({
6062
6086
  closeOnSelect: closeOnSelectProp = false,
6063
6087
  showGroupCounts = false,
6064
6088
  onCreateNew,
6065
- createNewLabel = "Create new"
6089
+ createNewLabel = "Create new",
6090
+ descriptionVariant = "inline"
6066
6091
  }) {
6067
6092
  const isSingleMode = value !== void 0 || onValueChange !== void 0;
6068
6093
  const singleSelectedOption = React36.useMemo(
@@ -6219,10 +6244,10 @@ function SearchSelect({
6219
6244
  "div",
6220
6245
  {
6221
6246
  className: cn(
6222
- "rounded-input border-rule-strong bg-surface relative flex h-9 w-full items-center border",
6223
- "transition-[color,background-color,border-color,box-shadow] duration-[var(--duration-fast)] ease-[var(--ease-out-quart)]",
6247
+ "rounded-input border-rule-strong bg-surface relative flex h-9 w-full items-center border outline-none",
6248
+ "transition-[color,background-color,border-color] duration-[var(--duration-fast)] ease-[var(--ease-out-quart)]",
6224
6249
  "motion-reduce:transition-none",
6225
- "focus-within:border-accent focus-within:[box-shadow:var(--shadow-focus-ring)]",
6250
+ "focus-within:[outline:1px_solid_var(--color-pro-fg)] focus-within:[outline-offset:-1px]",
6226
6251
  showValue && "hover:bg-bg-2 gap-2 pr-2 pl-3",
6227
6252
  disabled && "bg-bg-disabled cursor-not-allowed"
6228
6253
  ),
@@ -6233,7 +6258,7 @@ function SearchSelect({
6233
6258
  type: "button",
6234
6259
  onClick: () => !disabled && setOpen(true),
6235
6260
  disabled,
6236
- className: "flex h-full flex-1 items-center gap-2 text-left outline-none disabled:cursor-not-allowed",
6261
+ className: "flex h-full min-w-0 flex-1 items-center gap-2 text-left outline-none disabled:cursor-not-allowed",
6237
6262
  children: [
6238
6263
  singleValue.icon && /* @__PURE__ */ jsx(
6239
6264
  "span",
@@ -6246,7 +6271,15 @@ function SearchSelect({
6246
6271
  children: singleValue.icon
6247
6272
  }
6248
6273
  ),
6249
- /* @__PURE__ */ jsxs("span", { className: "text-fg flex-1 truncate text-[13px]", children: [
6274
+ descriptionVariant === "pill" && singleValue.description ? (
6275
+ // Pill variant: label truncates, description rides after it
6276
+ // as a discrete shrink-0 badge so dense metadata reads as a
6277
+ // tag instead of running into the label.
6278
+ /* @__PURE__ */ jsxs("span", { className: "flex min-w-0 flex-1 items-center gap-1.5 text-[13px]", children: [
6279
+ /* @__PURE__ */ jsx("span", { className: "text-fg truncate", children: singleValue.label }),
6280
+ /* @__PURE__ */ jsx("span", { className: "rounded-pill border-rule bg-bg-2 text-fg-3 shrink-0 border px-1.5 py-0.5 text-[11px] leading-none", children: singleValue.description })
6281
+ ] })
6282
+ ) : /* @__PURE__ */ jsxs("span", { className: "text-fg min-w-0 flex-1 truncate text-[13px]", children: [
6250
6283
  singleValue.label,
6251
6284
  singleValue.description && /* @__PURE__ */ jsxs("span", { className: "text-fg-4", children: [
6252
6285
  " \xB7 ",
@@ -7981,7 +8014,8 @@ function SidebarProvider({
7981
8014
  SidebarProvider.displayName = "SidebarProvider";
7982
8015
  var PEEK_ENTER_DELAY_MS = 100;
7983
8016
  var PEEK_LEAVE_DELAY_MS = 200;
7984
- var Sidebar = React36.forwardRef(function Sidebar2({ className, collapsible = false, onMouseEnter, onMouseLeave, style, ...props }, ref) {
8017
+ var Sidebar = React36.forwardRef(function Sidebar2({ className, collapsible = false, variant = "classic", onMouseEnter, onMouseLeave, style, ...props }, ref) {
8018
+ const isFloating = variant === "floating";
7985
8019
  const ctx = React36.useContext(SidebarContext);
7986
8020
  const state = collapsible && ctx ? ctx.state : "expanded";
7987
8021
  const peekLockCount = collapsible && ctx ? ctx.peekLockCount : 0;
@@ -8044,12 +8078,19 @@ var Sidebar = React36.forwardRef(function Sidebar2({ className, collapsible = fa
8044
8078
  "data-overlay": overlay ? "true" : void 0,
8045
8079
  "data-labels": labelsHidden ? "hide" : "show",
8046
8080
  "data-collapsible": collapsible ? "true" : void 0,
8081
+ "data-variant": variant,
8047
8082
  onMouseEnter: handleEnter,
8048
8083
  onMouseLeave: handleLeave,
8049
8084
  style: { width: effectiveWidth, ...style },
8050
8085
  className: cn(
8051
- "group/sidebar scrollbar-thin flex h-dvh shrink-0 flex-col overflow-y-auto",
8052
- "border-rule bg-bg-2 border-r px-3 pt-4 pb-4",
8086
+ "group/sidebar scrollbar-thin flex shrink-0 flex-col overflow-y-auto px-3 pt-4 pb-4",
8087
+ // Classic: full-height column flush to the left edge with a right
8088
+ // rule. The legacy look.
8089
+ !isFloating && "h-dvh border-rule bg-bg-2 border-r",
8090
+ // Floating: a detached, rounded card inset from the viewport with a
8091
+ // soft shadow — the modern SaaS pattern. The clear figure/ground gap
8092
+ // (Aesthetic-Usability) reads as its own surface above the canvas.
8093
+ isFloating && "border-rule bg-surface shadow-card m-2.5 h-[calc(100dvh-1.25rem)] rounded-2xl border",
8053
8094
  // 220ms feels right for a ~192px width sweep — slower than the
8054
8095
  // 150ms `--duration-fast` (which reads as a snap on this size of
8055
8096
  // movement) but well short of `--duration-slow` (which feels
@@ -8338,6 +8379,11 @@ var SidebarLink = React36.forwardRef(
8338
8379
  // when the column widens during peek. The label simply collapses
8339
8380
  // to width 0 via <SidebarLinkLabel>.
8340
8381
  "[&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:opacity-85",
8382
+ // Floating variant: softer corners + a taller hit area (Fitts's
8383
+ // law — a larger target is faster and lower-error to acquire), and
8384
+ // a full pill highlight for active instead of the left rail bar.
8385
+ "group-data-[variant=floating]/sidebar:gap-3 group-data-[variant=floating]/sidebar:rounded-lg group-data-[variant=floating]/sidebar:py-2",
8386
+ "group-data-[variant=floating]/sidebar:data-[active=true]:before:hidden",
8341
8387
  className
8342
8388
  ),
8343
8389
  ...props,
@@ -8347,10 +8393,12 @@ var SidebarLink = React36.forwardRef(
8347
8393
  "span",
8348
8394
  {
8349
8395
  className: cn(
8350
- // line-clamp-1 (not `truncate`) so multi-word labels clip at a
8351
- // word boundary; collapses cleanly with the rail-mode max-width
8352
- // animation since both rules only constrain visible content.
8353
- "min-w-0 flex-1 line-clamp-1",
8396
+ // Flex row so a trailing <SidebarLinkBadge> (ml-auto) aligns
8397
+ // to the right edge with a gap from the label, instead of
8398
+ // butting against it. A line-clamp box swallows the badge's
8399
+ // auto margin, which is why "Billing$48k" rendered glued.
8400
+ // Single-line label clips via overflow; badge stays put.
8401
+ "flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden whitespace-nowrap",
8354
8402
  "transition-[opacity,max-width] duration-[180ms] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
8355
8403
  "max-w-full opacity-100",
8356
8404
  "group-data-[labels=hide]/sidebar:max-w-0 group-data-[labels=hide]/sidebar:opacity-0 group-data-[labels=hide]/sidebar:invisible"
@@ -8486,7 +8534,10 @@ var SidebarLinkGroup = React36.forwardRef(
8486
8534
  "data-[active=true]:before:top-1/2 data-[active=true]:before:left-0",
8487
8535
  "data-[active=true]:before:h-4 data-[active=true]:before:w-[2px] data-[active=true]:before:-translate-y-1/2",
8488
8536
  "data-[active=true]:before:bg-pro-fg data-[active=true]:before:rounded-r-full",
8489
- "[&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:opacity-85"
8537
+ "[&_svg]:size-3.5 [&_svg]:shrink-0 [&_svg]:opacity-85",
8538
+ // Floating variant — match SidebarLink: taller hit area, pill active.
8539
+ "group-data-[variant=floating]/sidebar:gap-3 group-data-[variant=floating]/sidebar:rounded-lg group-data-[variant=floating]/sidebar:py-2",
8540
+ "group-data-[variant=floating]/sidebar:data-[active=true]:before:hidden"
8490
8541
  );
8491
8542
  const labelSpan = /* @__PURE__ */ jsx(
8492
8543
  "span",
@@ -10161,30 +10212,43 @@ function useStopwatch() {
10161
10212
  }, [setPhase]);
10162
10213
  return { phase, elapsedMs, isRunning: phase === "running", start, pause, resume, stop, reset };
10163
10214
  }
10164
- var TimeLogger = forwardRef(function TimeLogger2({ className, children, ...props }, ref) {
10215
+ var TimeLogger = forwardRef(function TimeLogger2({ className, orientation = "vertical", children, ...props }, ref) {
10165
10216
  return /* @__PURE__ */ jsx(
10166
10217
  "div",
10167
10218
  {
10168
10219
  ref,
10169
- className: cn("bg-surface text-fg-2 flex w-full flex-col", className),
10220
+ "data-orientation": orientation,
10221
+ className: cn(
10222
+ "group/timelogger bg-surface text-fg-2 flex w-full",
10223
+ orientation === "horizontal" ? "flex-row items-stretch" : "flex-col",
10224
+ className
10225
+ ),
10170
10226
  ...props,
10171
10227
  children
10172
10228
  }
10173
10229
  );
10174
10230
  });
10175
10231
  TimeLogger.displayName = "TimeLogger";
10232
+ var horizontalSegment = "group-data-[orientation=horizontal]/timelogger:border-t-0 group-data-[orientation=horizontal]/timelogger:border-l group-data-[orientation=horizontal]/timelogger:first:border-l-0";
10176
10233
  var TimeLoggerHeader = forwardRef(
10177
10234
  function TimeLoggerHeader2({ title = "Track Time", icon, loggedMinutes = 0, goalMinutes, className, ...props }, ref) {
10178
10235
  const hasGoal = goalMinutes != null;
10179
10236
  const pct = hasGoal && goalMinutes > 0 ? Math.min(100, loggedMinutes / goalMinutes * 100) : 0;
10180
10237
  return /* @__PURE__ */ jsxs("div", { ref, className: cn("flex flex-col", className), ...props, children: [
10181
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3", children: [
10182
- /* @__PURE__ */ jsxs("div", { className: "text-fg flex items-center gap-2 text-base font-semibold [&_svg]:size-[18px]", children: [
10183
- /* @__PURE__ */ jsx("span", { className: "text-pro-fg", "aria-hidden": "true", children: icon ?? /* @__PURE__ */ jsx(ClockIcon, {}) }),
10238
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3.5", children: [
10239
+ /* @__PURE__ */ jsxs("div", { className: "text-fg flex items-center gap-2.5 text-[17px] font-semibold", children: [
10240
+ /* @__PURE__ */ jsx(
10241
+ "span",
10242
+ {
10243
+ className: "bg-pro-bg text-pro-fg flex size-7 shrink-0 items-center justify-center rounded-lg [&_svg]:size-[17px]",
10244
+ "aria-hidden": "true",
10245
+ children: icon ?? /* @__PURE__ */ jsx(ClockIcon, {})
10246
+ }
10247
+ ),
10184
10248
  title
10185
10249
  ] }),
10186
10250
  hasGoal && /* @__PURE__ */ jsxs("div", { className: "text-fg-3 font-mono text-[13px] tabular-nums", children: [
10187
- /* @__PURE__ */ jsx("b", { className: "text-fg font-medium", children: formatDuration(loggedMinutes * 60) }),
10251
+ /* @__PURE__ */ jsx("b", { className: "text-fg font-semibold", children: formatDuration(loggedMinutes * 60) }),
10188
10252
  " /",
10189
10253
  " ",
10190
10254
  formatDuration(goalMinutes * 60)
@@ -10193,7 +10257,7 @@ var TimeLoggerHeader = forwardRef(
10193
10257
  hasGoal && /* @__PURE__ */ jsx(
10194
10258
  "div",
10195
10259
  {
10196
- className: "bg-bg-3 relative h-[3px] w-full",
10260
+ className: "bg-bg-3 relative h-1 w-full",
10197
10261
  role: "progressbar",
10198
10262
  "aria-label": "Daily goal progress",
10199
10263
  "aria-valuemin": 0,
@@ -10202,7 +10266,7 @@ var TimeLoggerHeader = forwardRef(
10202
10266
  children: /* @__PURE__ */ jsx(
10203
10267
  "div",
10204
10268
  {
10205
- className: "bg-pro-fg h-full rounded-r-full transition-[width] duration-[var(--duration-normal)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
10269
+ className: "h-full rounded-r-full bg-[image:var(--gradient-pro)] transition-[width] duration-[var(--duration-normal)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
10206
10270
  style: { width: `${pct}%` }
10207
10271
  }
10208
10272
  )
@@ -10222,7 +10286,11 @@ var TimeLoggerContextRow = forwardRef(
10222
10286
  "div",
10223
10287
  {
10224
10288
  ref,
10225
- className: cn("border-rule-soft flex items-center gap-2.5 border-t px-4 py-2.5", className),
10289
+ className: cn(
10290
+ "border-rule-soft flex items-center gap-2.5 border-t px-4 py-3",
10291
+ horizontalSegment,
10292
+ className
10293
+ ),
10226
10294
  ...props,
10227
10295
  children: [
10228
10296
  onClientSelect ? /* @__PURE__ */ jsxs(
@@ -10267,7 +10335,15 @@ var TimeLoggerTimer = forwardRef(
10267
10335
  "div",
10268
10336
  {
10269
10337
  ref,
10270
- className: cn("border-rule-soft flex items-center gap-2 border-t px-4 py-2.5", className),
10338
+ className: cn(
10339
+ "border-rule-soft flex items-center gap-2.5 border-t px-4 py-4",
10340
+ // In a horizontal bar this segment is usually the `flex-1` grower;
10341
+ // min-w-0 lets the clock shrink instead of pushing the trailing
10342
+ // segment off the edge.
10343
+ "group-data-[orientation=horizontal]/timelogger:min-w-0",
10344
+ horizontalSegment,
10345
+ className
10346
+ ),
10271
10347
  ...props,
10272
10348
  children: [
10273
10349
  /* @__PURE__ */ jsx(
@@ -10275,7 +10351,7 @@ var TimeLoggerTimer = forwardRef(
10275
10351
  {
10276
10352
  className: cn(
10277
10353
  "text-fg placeholder:text-fg-4 min-w-0 flex-1 border-0 bg-transparent outline-none",
10278
- showClock ? "font-mono text-[22px] font-medium tracking-tight tabular-nums" : "text-[15px]"
10354
+ showClock ? "font-mono text-[28px] font-semibold tracking-tight tabular-nums" : "text-[15px]"
10279
10355
  ),
10280
10356
  value: showClock ? formatClock(elapsedMs) : value ?? "",
10281
10357
  onChange: (event) => onValueChange?.(event.target.value),
@@ -10288,9 +10364,9 @@ var TimeLoggerTimer = forwardRef(
10288
10364
  Button,
10289
10365
  {
10290
10366
  type: "button",
10291
- variant: "secondary",
10367
+ variant: "ghost",
10292
10368
  size: "icon",
10293
- className: "rounded-full",
10369
+ className: "text-fg-3 hover:bg-bg-3 hover:text-fg size-10 rounded-full",
10294
10370
  "aria-label": phase === "paused" ? "Resume timer" : "Pause timer",
10295
10371
  disabled: phase === "idle" || phase === "stopped",
10296
10372
  onClick: phase === "paused" ? onResume : onPause,
@@ -10303,7 +10379,7 @@ var TimeLoggerTimer = forwardRef(
10303
10379
  type: "button",
10304
10380
  variant: "destructive",
10305
10381
  size: "icon",
10306
- className: "rounded-full",
10382
+ className: "shadow-card hover:shadow-pop size-12 rounded-full transition-[transform,box-shadow] active:scale-95 motion-reduce:transition-none",
10307
10383
  "aria-label": "Stop timer",
10308
10384
  onClick: onStop,
10309
10385
  children: /* @__PURE__ */ jsx(StopIcon, {})
@@ -10314,7 +10390,7 @@ var TimeLoggerTimer = forwardRef(
10314
10390
  type: "button",
10315
10391
  variant: "primary",
10316
10392
  size: "icon",
10317
- className: "rounded-full",
10393
+ className: "shadow-card hover:shadow-pop size-12 rounded-full bg-[image:var(--gradient-brand)] transition-[transform,box-shadow] active:scale-95 motion-reduce:transition-none",
10318
10394
  "aria-label": "Start timer",
10319
10395
  onClick: onStart,
10320
10396
  children: /* @__PURE__ */ jsx(PlayIcon, {})
@@ -10345,7 +10421,9 @@ var TimeLoggerField = forwardRef(
10345
10421
  trailing !== void 0 ? trailing : interactive ? /* @__PURE__ */ jsx(ChevronRightIcon, { className: "text-fg-4 size-4 shrink-0" }) : null
10346
10422
  ] });
10347
10423
  const classes = cn(
10348
- "border-rule-soft flex w-full items-center gap-3 border-t px-4 py-2.5 text-left",
10424
+ "border-rule-soft flex w-full items-center gap-3 border-t px-4 py-3 text-left",
10425
+ "group-data-[orientation=horizontal]/timelogger:w-auto",
10426
+ horizontalSegment,
10349
10427
  interactive && "hover:bg-surface-2 focus-visible:bg-surface-2 cursor-pointer transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] outline-none motion-reduce:transition-none",
10350
10428
  className
10351
10429
  );
@@ -10368,7 +10446,7 @@ var TimeLoggerField = forwardRef(
10368
10446
  TimeLoggerField.displayName = "TimeLoggerField";
10369
10447
  var TimeLoggerNotes = forwardRef(
10370
10448
  function TimeLoggerNotes2({ value, onValueChange, icon, placeholder = "Add notes", className, ...props }, ref) {
10371
- return /* @__PURE__ */ jsxs("div", { className: "border-rule-soft flex items-center gap-3 border-t px-4 py-2.5", children: [
10449
+ return /* @__PURE__ */ jsxs("div", { className: "border-rule-soft flex items-center gap-3 border-t px-4 py-3", children: [
10372
10450
  /* @__PURE__ */ jsx(
10373
10451
  "span",
10374
10452
  {
@@ -10486,7 +10564,8 @@ var TimeLoggerActions = forwardRef(
10486
10564
  {
10487
10565
  ref,
10488
10566
  className: cn(
10489
- "border-rule bg-surface-2 flex items-center gap-2 border-t px-4 py-2.5",
10567
+ "border-rule bg-surface-2 flex items-center gap-2 border-t px-4 py-3",
10568
+ horizontalSegment,
10490
10569
  className
10491
10570
  ),
10492
10571
  ...props,
@@ -10514,7 +10593,10 @@ var TimeLoggerEntry = forwardRef(
10514
10593
  "div",
10515
10594
  {
10516
10595
  ref,
10517
- className: cn("border-rule-soft flex items-center gap-3 border-t px-4 py-2", className),
10596
+ className: cn(
10597
+ "border-rule-soft hover:bg-surface-2 flex items-center gap-3 border-t px-4 py-2.5 transition-colors duration-[var(--duration-fast)] ease-[var(--ease-out-quart)] motion-reduce:transition-none",
10598
+ className
10599
+ ),
10518
10600
  ...props,
10519
10601
  children: [
10520
10602
  /* @__PURE__ */ jsx(
@@ -10565,7 +10647,7 @@ var TimeLoggerFooter = forwardRef(
10565
10647
  "div",
10566
10648
  {
10567
10649
  ref,
10568
- className: cn("border-rule flex gap-2 border-t px-4 py-2.5 [&>*]:flex-1", className),
10650
+ className: cn("border-rule flex gap-2 border-t px-4 py-3 [&>*]:flex-1", className),
10569
10651
  ...props,
10570
10652
  children
10571
10653
  }