@david-richard/notify-ds 1.0.2 → 1.0.4

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.mts CHANGED
@@ -180,13 +180,17 @@ interface SelectorGroupProps {
180
180
  declare function SelectorGroup({ children, className }: SelectorGroupProps): react_jsx_runtime.JSX.Element;
181
181
 
182
182
  /**
183
- * TabBar — Qu Notify segmented tab selector.
183
+ * TabBar — Qu Notify top-level tab selector (L1).
184
184
  *
185
185
  * Visual spec:
186
- * Container: gray-100 (#DEDEDE) pill, 4px padding all sides, full-radius
187
- * Selected tab: black fill, white text, full-radius pill
188
- * Unselected tab: transparent, primary text
189
- * Font: Inter Medium 14px
186
+ * Layout: standalone pills sitting in a row with gaps (no outer container).
187
+ * Selected tab: black fill, white text, full-radius pill.
188
+ * Unselected tab: gray-100 fill, primary text, full-radius pill.
189
+ * Font: Inter Medium 14px.
190
+ *
191
+ * Differs from Switcher: TabBar is for primary page-level navigation where
192
+ * each tab reads as its own standalone affordance. Switcher is for inline
193
+ * filters where the segments share an outer track.
190
194
  *
191
195
  * Usage (uncontrolled):
192
196
  * <TabBar tabs={["Sales", "Labor", "Store"]} defaultValue="Sales" />
@@ -236,18 +240,18 @@ interface TabPanelProps {
236
240
  declare function TabPanel({ children, className }: TabPanelProps): react_jsx_runtime.JSX.Element;
237
241
 
238
242
  /**
239
- * Switcher — Qu Notify segmented control (iOS-style).
243
+ * Switcher — Qu Notify segmented control (L2 — inline data filter).
240
244
  *
241
245
  * Visual spec:
242
- * Container: gray-100 (#DEDEDE) bg, 8px corner radius, 3px padding
243
- * Selected segment: black fill, white text, 6px corner radius
244
- * Unselected segment: transparent, secondary text (gray)
246
+ * Container: gray-100 (#DEDEDE) bg, full-radius pill, 3px padding
247
+ * Selected segment: black fill, white text, full-radius pill
248
+ * Unselected segment: transparent, primary text (black)
245
249
  * Font: Inter Medium 14px
246
250
  *
247
251
  * Differs from TabBar:
248
- * - TabBar: full-radius pill, used for primary page-level navigation
249
- * - Switcher: square-ish corners (8px), used for inline data filters
250
- * (e.g. Day / Week / Month, Net / Gross, All / Open / Closed)
252
+ * - TabBar: standalone pill tabs, no outer container — primary page navigation
253
+ * - Switcher: outer pill container holding inner pill segments — inline
254
+ * data filters (e.g. Day / Week / Month, Net / Gross, All / Open / Closed)
251
255
  *
252
256
  * Usage (uncontrolled):
253
257
  * <Switcher segments={["Day", "Week", "Month"]} defaultValue="Week" />
@@ -364,21 +368,26 @@ interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps
364
368
  }
365
369
  declare function Badge({ variant, size, icon, children, className, ...props }: BadgeProps): react_jsx_runtime.JSX.Element;
366
370
  /**
367
- * TrendBadge — convenience wrapper that picks variant from sign of the value.
371
+ * TrendBadge — inline trend indicator. Bare colored text + arrow, no pill bg.
372
+ *
373
+ * Used inside MetricTile and anywhere a percent delta needs to appear next to
374
+ * a primary value. The bare style keeps the trend visually subordinate to the
375
+ * value above it (the headline number is the hero; the trend is supporting
376
+ * commentary). For a pill-shaped status label, use <Badge> directly.
368
377
  *
369
378
  * Usage:
370
- * <TrendBadge value={11.8} /> → green "+11.8%"
371
- * <TrendBadge value={-5.6} /> → red "−5.6%"
379
+ * <TrendBadge value={11.8} /> → green "+11.8%"
380
+ * <TrendBadge value={-5.6} /> → red "−5.6%"
372
381
  * <TrendBadge value={0} /> → neutral "0.0%"
373
382
  */
374
- interface TrendBadgeProps extends Omit<BadgeProps, "variant" | "children"> {
383
+ interface TrendBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
375
384
  value: number;
376
385
  /** Number of decimal places (default: 1) */
377
386
  decimals?: number;
378
387
  /** Show arrow icon (default: true) */
379
388
  showArrow?: boolean;
380
389
  }
381
- declare function TrendBadge({ value, decimals, showArrow, ...props }: TrendBadgeProps): react_jsx_runtime.JSX.Element;
390
+ declare function TrendBadge({ value, decimals, showArrow, className, ...props }: TrendBadgeProps): react_jsx_runtime.JSX.Element;
382
391
 
383
392
  /**
384
393
  * MetricTile — the core data display unit of the Qu Notify dashboard.
package/dist/index.d.ts CHANGED
@@ -180,13 +180,17 @@ interface SelectorGroupProps {
180
180
  declare function SelectorGroup({ children, className }: SelectorGroupProps): react_jsx_runtime.JSX.Element;
181
181
 
182
182
  /**
183
- * TabBar — Qu Notify segmented tab selector.
183
+ * TabBar — Qu Notify top-level tab selector (L1).
184
184
  *
185
185
  * Visual spec:
186
- * Container: gray-100 (#DEDEDE) pill, 4px padding all sides, full-radius
187
- * Selected tab: black fill, white text, full-radius pill
188
- * Unselected tab: transparent, primary text
189
- * Font: Inter Medium 14px
186
+ * Layout: standalone pills sitting in a row with gaps (no outer container).
187
+ * Selected tab: black fill, white text, full-radius pill.
188
+ * Unselected tab: gray-100 fill, primary text, full-radius pill.
189
+ * Font: Inter Medium 14px.
190
+ *
191
+ * Differs from Switcher: TabBar is for primary page-level navigation where
192
+ * each tab reads as its own standalone affordance. Switcher is for inline
193
+ * filters where the segments share an outer track.
190
194
  *
191
195
  * Usage (uncontrolled):
192
196
  * <TabBar tabs={["Sales", "Labor", "Store"]} defaultValue="Sales" />
@@ -236,18 +240,18 @@ interface TabPanelProps {
236
240
  declare function TabPanel({ children, className }: TabPanelProps): react_jsx_runtime.JSX.Element;
237
241
 
238
242
  /**
239
- * Switcher — Qu Notify segmented control (iOS-style).
243
+ * Switcher — Qu Notify segmented control (L2 — inline data filter).
240
244
  *
241
245
  * Visual spec:
242
- * Container: gray-100 (#DEDEDE) bg, 8px corner radius, 3px padding
243
- * Selected segment: black fill, white text, 6px corner radius
244
- * Unselected segment: transparent, secondary text (gray)
246
+ * Container: gray-100 (#DEDEDE) bg, full-radius pill, 3px padding
247
+ * Selected segment: black fill, white text, full-radius pill
248
+ * Unselected segment: transparent, primary text (black)
245
249
  * Font: Inter Medium 14px
246
250
  *
247
251
  * Differs from TabBar:
248
- * - TabBar: full-radius pill, used for primary page-level navigation
249
- * - Switcher: square-ish corners (8px), used for inline data filters
250
- * (e.g. Day / Week / Month, Net / Gross, All / Open / Closed)
252
+ * - TabBar: standalone pill tabs, no outer container — primary page navigation
253
+ * - Switcher: outer pill container holding inner pill segments — inline
254
+ * data filters (e.g. Day / Week / Month, Net / Gross, All / Open / Closed)
251
255
  *
252
256
  * Usage (uncontrolled):
253
257
  * <Switcher segments={["Day", "Week", "Month"]} defaultValue="Week" />
@@ -364,21 +368,26 @@ interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement>, VariantProps
364
368
  }
365
369
  declare function Badge({ variant, size, icon, children, className, ...props }: BadgeProps): react_jsx_runtime.JSX.Element;
366
370
  /**
367
- * TrendBadge — convenience wrapper that picks variant from sign of the value.
371
+ * TrendBadge — inline trend indicator. Bare colored text + arrow, no pill bg.
372
+ *
373
+ * Used inside MetricTile and anywhere a percent delta needs to appear next to
374
+ * a primary value. The bare style keeps the trend visually subordinate to the
375
+ * value above it (the headline number is the hero; the trend is supporting
376
+ * commentary). For a pill-shaped status label, use <Badge> directly.
368
377
  *
369
378
  * Usage:
370
- * <TrendBadge value={11.8} /> → green "+11.8%"
371
- * <TrendBadge value={-5.6} /> → red "−5.6%"
379
+ * <TrendBadge value={11.8} /> → green "+11.8%"
380
+ * <TrendBadge value={-5.6} /> → red "−5.6%"
372
381
  * <TrendBadge value={0} /> → neutral "0.0%"
373
382
  */
374
- interface TrendBadgeProps extends Omit<BadgeProps, "variant" | "children"> {
383
+ interface TrendBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
375
384
  value: number;
376
385
  /** Number of decimal places (default: 1) */
377
386
  decimals?: number;
378
387
  /** Show arrow icon (default: true) */
379
388
  showArrow?: boolean;
380
389
  }
381
- declare function TrendBadge({ value, decimals, showArrow, ...props }: TrendBadgeProps): react_jsx_runtime.JSX.Element;
390
+ declare function TrendBadge({ value, decimals, showArrow, className, ...props }: TrendBadgeProps): react_jsx_runtime.JSX.Element;
382
391
 
383
392
  /**
384
393
  * MetricTile — the core data display unit of the Qu Notify dashboard.
package/dist/index.js CHANGED
@@ -518,7 +518,7 @@ var Toggle = React4__namespace.forwardRef(
518
518
  Toggle.displayName = "Toggle";
519
519
  var selectorVariants = classVarianceAuthority.cva(
520
520
  [
521
- "inline-flex items-center gap-1.5 rounded-full select-none cursor-pointer",
521
+ "inline-flex items-center gap-1.5 rounded-xl select-none cursor-pointer",
522
522
  "py-2 pl-3.5 pr-2.5",
523
523
  "font-['Red_Hat_Text'] text-[14px] font-medium leading-tight",
524
524
  "border-[1.5px] transition-colors duration-[120ms]",
@@ -639,8 +639,7 @@ function TabBar({
639
639
  role: "tablist",
640
640
  "aria-label": "Tabs",
641
641
  className: cn(
642
- "inline-flex items-center gap-1 rounded-full p-1",
643
- "bg-[var(--color-inactive,#DEDEDE)]",
642
+ "inline-flex items-center gap-2",
644
643
  stretch && "w-full",
645
644
  className
646
645
  ),
@@ -659,7 +658,7 @@ function TabBar({
659
658
  "outline-none transition-colors duration-[120ms]",
660
659
  "focus-visible:ring-2 focus-visible:ring-[var(--color-ring,#40CCF2)] focus-visible:ring-offset-1",
661
660
  stretch && "flex-1 text-center",
662
- isSelected ? "bg-[var(--color-foreground,#000)] text-white" : "bg-transparent text-[var(--color-text-primary,#000)] hover:bg-black/5"
661
+ isSelected ? "bg-[var(--color-foreground,#000)] text-white" : "bg-[var(--color-inactive,#DEDEDE)] text-[var(--color-text-primary,#000)] hover:brightness-95"
663
662
  ),
664
663
  children: tab
665
664
  },
@@ -710,7 +709,7 @@ function Switcher({
710
709
  {
711
710
  role: "group",
712
711
  className: cn(
713
- "inline-flex items-center gap-0.5 rounded-[8px] p-[3px]",
712
+ "inline-flex items-center gap-0.5 rounded-full p-[3px]",
714
713
  "bg-[var(--color-inactive,#DEDEDE)]",
715
714
  stretch && "w-full",
716
715
  className
@@ -728,13 +727,13 @@ function Switcher({
728
727
  "aria-checked": isSelected,
729
728
  onClick: () => handleSelect(val),
730
729
  className: cn(
731
- "inline-flex items-center justify-center gap-1.5 rounded-[6px]",
730
+ "inline-flex items-center justify-center gap-1.5 rounded-full",
732
731
  "px-4 py-[7px] cursor-pointer select-none",
733
732
  "font-['Inter'] text-[14px] font-medium leading-tight",
734
733
  "outline-none transition-colors duration-[120ms]",
735
734
  "focus-visible:ring-2 focus-visible:ring-[var(--color-ring,#40CCF2)] focus-visible:ring-offset-1",
736
735
  stretch && "flex-1",
737
- isSelected ? "bg-[var(--color-foreground,#000)] text-white" : "bg-transparent text-[var(--color-text-secondary,#6B7280)] hover:text-[var(--color-text-primary,#000)]"
736
+ isSelected ? "bg-[var(--color-foreground,#000)] text-white" : "bg-transparent text-[var(--color-text-primary,#000)] hover:bg-black/5"
738
737
  ),
739
738
  children: [
740
739
  icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 [&_svg]:size-[14px]", children: icon }),
@@ -874,11 +873,27 @@ function Badge({ variant, size, icon, children, className, ...props }) {
874
873
  children
875
874
  ] });
876
875
  }
877
- function TrendBadge({ value, decimals = 1, showArrow = true, ...props }) {
878
- const variant = value > 0 ? "success" : value < 0 ? "error" : "neutral";
876
+ function TrendBadge({ value, decimals = 1, showArrow = true, className, ...props }) {
877
+ const colorClass = value > 0 ? "text-[var(--color-success,#16A34A)]" : value < 0 ? "text-[var(--color-destructive,#EF2149)]" : "text-[var(--color-text-tertiary,#6B7280)]";
879
878
  const formatted = `${value > 0 ? "+" : ""}${value.toFixed(decimals)}%`;
880
879
  const arrow = showArrow ? value > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ArrowUpIcon, {}) : value < 0 ? /* @__PURE__ */ jsxRuntime.jsx(ArrowDownIcon, {}) : null : null;
881
- return /* @__PURE__ */ jsxRuntime.jsx(Badge, { variant, icon: arrow, ...props, children: formatted });
880
+ return /* @__PURE__ */ jsxRuntime.jsxs(
881
+ "span",
882
+ {
883
+ className: cn(
884
+ "inline-flex items-center gap-1 whitespace-nowrap select-none",
885
+ "font-['Inter'] text-[12px] font-medium leading-tight",
886
+ "[&_svg]:size-3",
887
+ colorClass,
888
+ className
889
+ ),
890
+ ...props,
891
+ children: [
892
+ arrow,
893
+ formatted
894
+ ]
895
+ }
896
+ );
882
897
  }
883
898
  function ArrowUpIcon() {
884
899
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "2,7 5,3 8,7" }) });
@@ -943,7 +958,7 @@ function MetricTile({
943
958
  children: !loading && label
944
959
  }
945
960
  ),
946
- icon && !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[var(--color-text-tertiary,#6B7280)] [&_svg]:size-4", "aria-hidden": "true", children: icon })
961
+ !loading && (icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[var(--color-text-tertiary,#6B7280)] [&_svg]:size-4", "aria-hidden": "true", children: icon }) : onClick ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 text-[var(--color-text-tertiary,#6B7280)] [&_svg]:size-3.5", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx(ChevronRightIcon, {}) }) : null)
947
962
  ] }),
948
963
  /* @__PURE__ */ jsxRuntime.jsx(
949
964
  "span",
@@ -958,8 +973,8 @@ function MetricTile({
958
973
  }
959
974
  ),
960
975
  (trend !== void 0 || trendLabel) && !loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
961
- trend !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(TrendBadge, { value: trend, size: "sm" }),
962
- trendLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-['Inter'] text-[11px] text-[var(--color-text-tertiary,#6B7280)]", children: trendLabel })
976
+ trendLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-['Inter'] text-[12px] text-[var(--color-text-tertiary,#6B7280)]", children: trendLabel }),
977
+ trend !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(TrendBadge, { value: trend })
963
978
  ] }),
964
979
  loading && trend !== void 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 h-4 w-16 rounded bg-gray-200" })
965
980
  ]
@@ -975,6 +990,9 @@ function MetricTileGrid({ cols = 2, children, className }) {
975
990
  }[cols];
976
991
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("grid gap-3", colClass, className), children });
977
992
  }
993
+ function ChevronRightIcon() {
994
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "5,3 9,7 5,11" }) });
995
+ }
978
996
 
979
997
  exports.Badge = Badge;
980
998
  exports.BottomNav = BottomNav;