@estiva-app/ui 0.6.0 → 0.7.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.
@@ -0,0 +1,54 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ /**
3
+ * A reaction: an emoji, how many people chose it, and whether you are one of
4
+ * them.
5
+ *
6
+ * **This exists because both apps had already built it, and neither could use
7
+ * the components that were here.** A reaction is a pill with a count that
8
+ * toggles — `Chip` is a pill and rules itself out for anything clickable,
9
+ * `Button` is clickable and is a 6px-radius rectangle, and `IconButton` has
10
+ * nowhere to put the count. So Peek re-typed Chip's class list with a border
11
+ * added, and Ship reached for a small Button with the count as its label. The
12
+ * two apps' reactions do not look alike today, and neither is what was drawn.
13
+ *
14
+ * ## The one thing it does that nothing else here does
15
+ *
16
+ * **It says the reaction is yours.** That is the state a reaction has and a
17
+ * chip does not: `pressed` fills it with the accent's muted tint and gives it
18
+ * an accent edge, so a glance separates "two people, one of them me" from "two
19
+ * people". Ship approximated it as `outlined` versus `muted` — measured at a
20
+ * 1px hairline against no border at all — which is legible and is not the
21
+ * signal Peek's accent fill gives.
22
+ *
23
+ * It is a real `<button>` with `aria-pressed`, so the state reaches assistive
24
+ * tech as a toggle rather than as a colour.
25
+ *
26
+ * ## `aria-label` is required, and the reason is specific
27
+ *
28
+ * The emoji is decorative here — it is `aria-hidden`, because a glyph read
29
+ * aloud is noise and its spoken name differs per screen reader — and the only
30
+ * visible text is the count. Without a label the control is announced as
31
+ * **"2"**, which is what Ship shipped and its own tests caught. Pass the
32
+ * meaning and the count: `"Makes sense, 2"`.
33
+ *
34
+ * ## Geometry
35
+ *
36
+ * Chip's pill, at a control's height: fully rounded, 24px to match `Button`
37
+ * `small`, the same 8px horizontal padding, the `chip` type token for the
38
+ * count so it sits at 11px/500 like every other count in the system.
39
+ */
40
+ export interface ReactionProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
41
+ /** The emoji, drawn decoratively — name the control with `aria-label`. */
42
+ emoji: ReactNode;
43
+ /** How many people reacted. Drawn as-is; `0` is not a reaction and is not drawn. */
44
+ count: number;
45
+ /** You are one of them: the accent tint and edge, and `aria-pressed`. */
46
+ pressed?: boolean;
47
+ /**
48
+ * Names the control. **Required** — the emoji is decorative and the count is
49
+ * the only visible text, so without this it is announced as a bare number.
50
+ */
51
+ 'aria-label': string;
52
+ }
53
+ export declare function Reaction({ emoji, count, pressed, className, type, ...props }: ReactionProps): import("react").JSX.Element;
54
+ //# sourceMappingURL=Reaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Reaction.d.ts","sourceRoot":"","sources":["../src/Reaction.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAG5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,oBAAoB,CAAC,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC9F,0EAA0E;IAC1E,KAAK,EAAE,SAAS,CAAA;IAChB,oFAAoF;IACpF,KAAK,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAe,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BA8BnG"}
package/dist/index.d.ts CHANGED
@@ -42,6 +42,7 @@ export { Sidebar, type SidebarProps } from './Sidebar';
42
42
  export { TopBar, type TopBarProps } from './TopBar';
43
43
  export { PersonTrigger, type PersonTriggerProps } from './PersonTrigger';
44
44
  export { Property, type PropertyProps } from './Property';
45
+ export { Reaction, type ReactionProps } from './Reaction';
45
46
  export { SearchInput, type SearchInputProps } from './SearchInput';
46
47
  export { SectionHeader, type SectionAction, type SectionHeaderProps } from './SectionHeader';
47
48
  export { SectionLabel } from './SectionLabel';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1592,11 +1592,37 @@ function Property({ label, layout = "row", children, className }) {
1592
1592
  ] });
1593
1593
  }
1594
1594
 
1595
+ // src/Reaction.tsx
1596
+ import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1597
+ function Reaction({ emoji, count, pressed = false, className, type, ...props }) {
1598
+ return /* @__PURE__ */ jsxs21(
1599
+ "button",
1600
+ {
1601
+ type: type ?? "button",
1602
+ "aria-pressed": pressed,
1603
+ className: cn(
1604
+ // Chip's pill at a control's height, so a reaction and a status chip
1605
+ // read as the same family — 24px matches Button `small`.
1606
+ "inline-flex h-6 items-center justify-center gap-1.5 rounded-full px-2",
1607
+ "border transition-colors",
1608
+ "disabled:cursor-not-allowed disabled:opacity-50",
1609
+ pressed ? "border-accent-primary bg-accent-muted text-accent-primary hover:border-accent-hover" : "border-border-default bg-bg-inset text-text-primary hover:border-border-strong hover:bg-bg-hover",
1610
+ className
1611
+ ),
1612
+ ...props,
1613
+ children: [
1614
+ /* @__PURE__ */ jsx33("span", { "aria-hidden": "true", className: "shrink-0 text-[16px] leading-none", children: emoji }),
1615
+ /* @__PURE__ */ jsx33("span", { className: "text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tabular-nums", children: count })
1616
+ ]
1617
+ }
1618
+ );
1619
+ }
1620
+
1595
1621
  // src/SearchInput.tsx
1596
1622
  import "react";
1597
- import { jsx as jsx33, jsxs as jsxs21 } from "react/jsx-runtime";
1623
+ import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1598
1624
  function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
1599
- return /* @__PURE__ */ jsxs21(
1625
+ return /* @__PURE__ */ jsxs22(
1600
1626
  "div",
1601
1627
  {
1602
1628
  className: cn(
@@ -1606,7 +1632,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
1606
1632
  className
1607
1633
  ),
1608
1634
  children: [
1609
- /* @__PURE__ */ jsx33(
1635
+ /* @__PURE__ */ jsx34(
1610
1636
  "input",
1611
1637
  {
1612
1638
  className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
@@ -1614,7 +1640,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
1614
1640
  ...props
1615
1641
  }
1616
1642
  ),
1617
- shortcut && /* @__PURE__ */ jsx33(Kbd, { children: shortcut })
1643
+ shortcut && /* @__PURE__ */ jsx34(Kbd, { children: shortcut })
1618
1644
  ]
1619
1645
  }
1620
1646
  );
@@ -1623,10 +1649,10 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
1623
1649
  // src/SectionHeader.tsx
1624
1650
  import { useState as useState10 } from "react";
1625
1651
  import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
1626
- import { jsx as jsx34, jsxs as jsxs22 } from "react/jsx-runtime";
1652
+ import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1627
1653
  function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", className }) {
1628
1654
  const [isHovered, setIsHovered] = useState10(false);
1629
- return /* @__PURE__ */ jsxs22(
1655
+ return /* @__PURE__ */ jsxs23(
1630
1656
  "div",
1631
1657
  {
1632
1658
  className: cn(
@@ -1639,8 +1665,8 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
1639
1665
  onMouseEnter: () => setIsHovered(true),
1640
1666
  onMouseLeave: () => setIsHovered(false),
1641
1667
  children: [
1642
- /* @__PURE__ */ jsxs22("div", { className: "flex shrink-0 items-center gap-1", children: [
1643
- chevron && /* @__PURE__ */ jsx34(
1668
+ /* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-1", children: [
1669
+ chevron && /* @__PURE__ */ jsx35(
1644
1670
  IconChevronRight2,
1645
1671
  {
1646
1672
  size: 12,
@@ -1648,9 +1674,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
1648
1674
  className: cn("text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
1649
1675
  }
1650
1676
  ),
1651
- /* @__PURE__ */ jsx34(SectionLabel, { children: title })
1677
+ /* @__PURE__ */ jsx35(SectionLabel, { children: title })
1652
1678
  ] }),
1653
- (showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */ jsx34("div", { className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ jsx34(
1679
+ (showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */ jsx35("div", { className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ jsx35(
1654
1680
  IconButton,
1655
1681
  {
1656
1682
  tooltip: action.tooltip,
@@ -1669,9 +1695,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
1669
1695
  }
1670
1696
 
1671
1697
  // src/Tabs.tsx
1672
- import { jsx as jsx35, jsxs as jsxs23 } from "react/jsx-runtime";
1698
+ import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1673
1699
  function Tabs({ tabs, active, onChange, size = "default", className }) {
1674
- return /* @__PURE__ */ jsx35("div", { role: "tablist", className: cn("flex items-center gap-2", className), children: tabs.map((tab) => /* @__PURE__ */ jsxs23(
1700
+ return /* @__PURE__ */ jsx36("div", { role: "tablist", className: cn("flex items-center gap-2", className), children: tabs.map((tab) => /* @__PURE__ */ jsxs24(
1675
1701
  "button",
1676
1702
  {
1677
1703
  type: "button",
@@ -1690,9 +1716,9 @@ function Tabs({ tabs, active, onChange, size = "default", className }) {
1690
1716
  ),
1691
1717
  children: [
1692
1718
  tab.icon,
1693
- /* @__PURE__ */ jsxs23("span", { className: "flex items-baseline", children: [
1719
+ /* @__PURE__ */ jsxs24("span", { className: "flex items-baseline", children: [
1694
1720
  tab.label,
1695
- tab.count !== void 0 ? /* @__PURE__ */ jsx35("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
1721
+ tab.count !== void 0 ? /* @__PURE__ */ jsx36("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
1696
1722
  ] })
1697
1723
  ]
1698
1724
  },
@@ -1704,7 +1730,7 @@ function Tabs({ tabs, active, onChange, size = "default", className }) {
1704
1730
  import { createContext as createContext3, useCallback as useCallback5, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo3, useState as useState11 } from "react";
1705
1731
  import { createPortal as createPortal6 } from "react-dom";
1706
1732
  import { IconCircleCheck } from "@tabler/icons-react";
1707
- import { jsx as jsx36, jsxs as jsxs24 } from "react/jsx-runtime";
1733
+ import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
1708
1734
  var SURFACE_BY_TYPE = {
1709
1735
  success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
1710
1736
  brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
@@ -1722,7 +1748,7 @@ var ACTION_BORDER_BY_TYPE = {
1722
1748
  };
1723
1749
  function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
1724
1750
  const hasAction = !!(actionLabel && onAction);
1725
- return /* @__PURE__ */ jsxs24(
1751
+ return /* @__PURE__ */ jsxs25(
1726
1752
  "div",
1727
1753
  {
1728
1754
  className: cn(
@@ -1734,11 +1760,11 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
1734
1760
  className
1735
1761
  ),
1736
1762
  children: [
1737
- /* @__PURE__ */ jsxs24("div", { className: "flex items-center gap-2 shrink-0", children: [
1738
- leadingIcon && /* @__PURE__ */ jsx36(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_BY_TYPE[type]) }),
1739
- /* @__PURE__ */ jsx36("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
1763
+ /* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 shrink-0", children: [
1764
+ leadingIcon && /* @__PURE__ */ jsx37(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_BY_TYPE[type]) }),
1765
+ /* @__PURE__ */ jsx37("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
1740
1766
  ] }),
1741
- hasAction && /* @__PURE__ */ jsx36(
1767
+ hasAction && /* @__PURE__ */ jsx37(
1742
1768
  "button",
1743
1769
  {
1744
1770
  type: "button",
@@ -1748,7 +1774,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
1748
1774
  ACTION_BORDER_BY_TYPE[type],
1749
1775
  type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
1750
1776
  ),
1751
- children: /* @__PURE__ */ jsx36("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
1777
+ children: /* @__PURE__ */ jsx37("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
1752
1778
  }
1753
1779
  )
1754
1780
  ]
@@ -1775,10 +1801,10 @@ function ToastProvider({ children }) {
1775
1801
  return () => clearTimeout(timer);
1776
1802
  }, [toast]);
1777
1803
  const value = useMemo3(() => ({ showToast, dismissToast }), [showToast, dismissToast]);
1778
- return /* @__PURE__ */ jsxs24(ToastContext.Provider, { value, children: [
1804
+ return /* @__PURE__ */ jsxs25(ToastContext.Provider, { value, children: [
1779
1805
  children,
1780
1806
  toast && createPortal6(
1781
- /* @__PURE__ */ jsx36("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx36(
1807
+ /* @__PURE__ */ jsx37("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx37(
1782
1808
  Toast,
1783
1809
  {
1784
1810
  className: "pointer-events-auto",
@@ -1835,6 +1861,7 @@ export {
1835
1861
  Property,
1836
1862
  Rail,
1837
1863
  RailItem,
1864
+ Reaction,
1838
1865
  SearchInput,
1839
1866
  SectionHeader,
1840
1867
  SectionLabel,