@salemcobalt/ui 0.2.0-rc.4 → 0.2.0-rc.6

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.js CHANGED
@@ -546,6 +546,9 @@ var iconNames = [
546
546
  "x"
547
547
  ];
548
548
 
549
+ // src/components/IconButton/IconButton.tsx
550
+ import { useRender as useRender2 } from "@base-ui/react/use-render";
551
+
549
552
  // src/components/Tooltip/Tooltip.tsx
550
553
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
551
554
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
@@ -583,7 +586,7 @@ var Provider = BaseTooltip.Provider;
583
586
  var Tooltip = Object.assign(TooltipBase, { Provider });
584
587
 
585
588
  // src/components/IconButton/IconButton.tsx
586
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
589
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
587
590
  function IconButton({
588
591
  label,
589
592
  children,
@@ -593,9 +596,11 @@ function IconButton({
593
596
  tooltipSide = "top",
594
597
  round = false,
595
598
  loading = false,
596
- type = "button",
599
+ type,
597
600
  className,
598
601
  onClick,
602
+ render,
603
+ ref,
599
604
  ...rest
600
605
  }) {
601
606
  const handleClick = (event) => {
@@ -605,10 +610,13 @@ function IconButton({
605
610
  }
606
611
  onClick?.(event);
607
612
  };
608
- const button = /* @__PURE__ */ jsxs7(
609
- "button",
610
- {
611
- type,
613
+ const button = useRender2({
614
+ render,
615
+ ref,
616
+ defaultTagName: "button",
617
+ props: {
618
+ // `type` only means something on a real button; a rendered link keeps its own attributes.
619
+ type: render ? type : type ?? "button",
612
620
  className: cx("sc-button", "sc-icon-button", className),
613
621
  "data-variant": variant,
614
622
  "data-size": size,
@@ -618,19 +626,19 @@ function IconButton({
618
626
  "aria-label": label,
619
627
  onClick: handleClick,
620
628
  ...rest,
621
- children: [
629
+ children: /* @__PURE__ */ jsxs7(Fragment2, { children: [
622
630
  /* @__PURE__ */ jsx8("span", { className: "sc-button__icon", "aria-hidden": "true", children }),
623
631
  loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null
624
- ]
632
+ ] })
625
633
  }
626
- );
634
+ });
627
635
  if (!tooltip) return button;
628
636
  return /* @__PURE__ */ jsx8(Tooltip, { content: tooltip === true ? label : tooltip, side: tooltipSide, children: button });
629
637
  }
630
638
 
631
639
  // src/components/Menu/Menu.tsx
632
640
  import { Menu as BaseMenu } from "@base-ui/react/menu";
633
- import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
641
+ import { Fragment as Fragment3, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
634
642
  function Root2({ open, defaultOpen, onOpenChange, disabled, modal = true, children }) {
635
643
  return /* @__PURE__ */ jsx9(
636
644
  BaseMenu.Root,
@@ -670,7 +678,7 @@ function ItemBody({
670
678
  trailing,
671
679
  children
672
680
  }) {
673
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
681
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
674
682
  /* @__PURE__ */ jsx9("span", { className: "sc-menu__icon", "aria-hidden": "true", children: icon }),
675
683
  /* @__PURE__ */ jsx9("span", { className: "sc-menu__label", children }),
676
684
  trailing !== void 0 ? /* @__PURE__ */ jsx9("span", { className: "sc-menu__trailing", children: trailing }) : null
@@ -857,9 +865,14 @@ function Textarea({
857
865
  className,
858
866
  rows = 3,
859
867
  resize = "vertical",
868
+ variant = "default",
860
869
  onValueChange,
870
+ spellCheck,
871
+ autoCorrect,
872
+ autoCapitalize,
861
873
  ...rest
862
874
  }) {
875
+ const code = variant === "code";
863
876
  return /* @__PURE__ */ jsx12(
864
877
  FieldShell,
865
878
  {
@@ -875,9 +888,19 @@ function Textarea({
875
888
  children: /* @__PURE__ */ jsx12(
876
889
  Field3.Control,
877
890
  {
878
- render: /* @__PURE__ */ jsx12("textarea", { rows, ...rest }),
891
+ render: /* @__PURE__ */ jsx12(
892
+ "textarea",
893
+ {
894
+ rows,
895
+ spellCheck: spellCheck ?? (code ? false : void 0),
896
+ autoCorrect: autoCorrect ?? (code ? "off" : void 0),
897
+ autoCapitalize: autoCapitalize ?? (code ? "off" : void 0),
898
+ ...rest
899
+ }
900
+ ),
879
901
  className: "sc-input sc-textarea",
880
902
  "data-resize": resize,
903
+ "data-variant": code ? "code" : void 0,
881
904
  required,
882
905
  onValueChange: onValueChange ? (value) => onValueChange(value) : void 0
883
906
  }
@@ -888,6 +911,7 @@ function Textarea({
888
911
 
889
912
  // src/components/Select/Select.tsx
890
913
  import { Select as BaseSelect } from "@base-ui/react/select";
914
+ import { useState } from "react";
891
915
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
892
916
  function isGroup(entry) {
893
917
  return "options" in entry;
@@ -914,11 +938,27 @@ function Select({
914
938
  defaultValue,
915
939
  onValueChange,
916
940
  placeholder = "Choose\u2026",
941
+ clearable = false,
942
+ clearLabel = "Clear",
917
943
  readOnly,
918
944
  fullWidth = false,
919
945
  id
920
946
  }) {
921
947
  const items = options.flatMap((entry) => isGroup(entry) ? entry.options : [entry]);
948
+ const [internal, setInternal] = useState(defaultValue ?? null);
949
+ const controlled = value !== void 0;
950
+ const current = controlled ? value : internal;
951
+ const setValue = (next) => {
952
+ if (!controlled) setInternal(next);
953
+ onValueChange?.(next);
954
+ };
955
+ const canClear = clearable && current != null && !disabled && !readOnly;
956
+ const onTriggerKeyDown = (event) => {
957
+ if (canClear && (event.key === "Backspace" || event.key === "Delete")) {
958
+ event.preventDefault();
959
+ setValue(null);
960
+ }
961
+ };
922
962
  return /* @__PURE__ */ jsx13(
923
963
  FieldShell,
924
964
  {
@@ -936,26 +976,39 @@ function Select({
936
976
  BaseSelect.Root,
937
977
  {
938
978
  items,
939
- value,
940
- defaultValue,
941
- onValueChange: onValueChange ? (next) => onValueChange(next) : void 0,
979
+ value: current,
980
+ onValueChange: (next) => setValue(next),
942
981
  disabled,
943
982
  required,
944
983
  readOnly,
945
984
  children: [
946
- /* @__PURE__ */ jsxs11(
947
- BaseSelect.Trigger,
948
- {
949
- id,
950
- className: "sc-select",
951
- "data-size": size,
952
- "data-full-width": fullWidth || void 0,
953
- children: [
954
- /* @__PURE__ */ jsx13(BaseSelect.Value, { className: "sc-select__value", placeholder }),
955
- /* @__PURE__ */ jsx13(BaseSelect.Icon, { className: "sc-select__icon", children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) })
956
- ]
957
- }
958
- ),
985
+ /* @__PURE__ */ jsxs11("span", { className: "sc-select__wrap", "data-full-width": fullWidth || void 0, children: [
986
+ /* @__PURE__ */ jsxs11(
987
+ BaseSelect.Trigger,
988
+ {
989
+ id,
990
+ className: "sc-select",
991
+ "data-size": size,
992
+ "data-full-width": fullWidth || void 0,
993
+ "data-clearable": canClear || void 0,
994
+ onKeyDown: onTriggerKeyDown,
995
+ children: [
996
+ /* @__PURE__ */ jsx13(BaseSelect.Value, { className: "sc-select__value", placeholder }),
997
+ /* @__PURE__ */ jsx13(BaseSelect.Icon, { className: "sc-select__icon", children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) })
998
+ ]
999
+ }
1000
+ ),
1001
+ canClear ? /* @__PURE__ */ jsx13(
1002
+ "button",
1003
+ {
1004
+ type: "button",
1005
+ className: "sc-select__clear",
1006
+ "aria-label": clearLabel,
1007
+ onClick: () => setValue(null),
1008
+ children: /* @__PURE__ */ jsx13(XIcon, { size: "sm" })
1009
+ }
1010
+ ) : null
1011
+ ] }),
959
1012
  /* @__PURE__ */ jsx13(BaseSelect.Portal, { children: /* @__PURE__ */ jsx13(
960
1013
  BaseSelect.Positioner,
961
1014
  {
@@ -1055,7 +1108,7 @@ function Switch({
1055
1108
 
1056
1109
  // src/components/Tabs/Tabs.tsx
1057
1110
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
1058
- import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1111
+ import { Fragment as Fragment4, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
1059
1112
  function Root3({ className, onValueChange, ...rest }) {
1060
1113
  return /* @__PURE__ */ jsx16(
1061
1114
  BaseTabs.Root,
@@ -1076,7 +1129,7 @@ function Tab({ icon, count, className, children, ...rest }) {
1076
1129
  return /* @__PURE__ */ jsxs14(BaseTabs.Tab, { className: cx("sc-tabs__tab", className), ...rest, children: [
1077
1130
  icon ? /* @__PURE__ */ jsx16("span", { className: "sc-tabs__icon", "aria-hidden": "true", children: icon }) : null,
1078
1131
  /* @__PURE__ */ jsx16("span", { className: "sc-tabs__label", children }),
1079
- count != null ? /* @__PURE__ */ jsxs14(Fragment3, { children: [
1132
+ count != null ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
1080
1133
  " ",
1081
1134
  /* @__PURE__ */ jsx16("span", { className: "sc-tabs__count", children: count })
1082
1135
  ] }) : null
@@ -1108,13 +1161,14 @@ function Separator2({ className, ...rest }) {
1108
1161
  return /* @__PURE__ */ jsx17(BaseToolbar.Separator, { className: cx("sc-toolbar__separator", className), ...rest });
1109
1162
  }
1110
1163
  var Button2 = BaseToolbar.Button;
1164
+ var Link = BaseToolbar.Link;
1111
1165
  function Spacer({ className }) {
1112
1166
  return /* @__PURE__ */ jsx17("div", { className: cx("sc-toolbar__spacer", className), "aria-hidden": "true" });
1113
1167
  }
1114
- var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Spacer };
1168
+ var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Link, Spacer };
1115
1169
 
1116
1170
  // src/components/Banner/Banner.tsx
1117
- import { useState } from "react";
1171
+ import { useState as useState2 } from "react";
1118
1172
  import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1119
1173
  var toneIcons = {
1120
1174
  info: /* @__PURE__ */ jsx18(InfoIcon, {}),
@@ -1136,7 +1190,7 @@ function Banner({
1136
1190
  children,
1137
1191
  ...rest
1138
1192
  }) {
1139
- const [dismissed, setDismissed] = useState(false);
1193
+ const [dismissed, setDismissed] = useState2(false);
1140
1194
  const visible = open ?? !dismissed;
1141
1195
  if (!visible) return null;
1142
1196
  const glyph = icon === false ? null : icon ?? toneIcons[tone];
@@ -1435,7 +1489,7 @@ var Table = { Root: Root5, Caption, Head, Body: Body2, Foot, Row, Header, Cell }
1435
1489
 
1436
1490
  // src/components/Stat/Stat.tsx
1437
1491
  import { createElement as createElement5 } from "react";
1438
- import { Fragment as Fragment4, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1492
+ import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
1439
1493
  var trendIcons = {
1440
1494
  up: /* @__PURE__ */ jsx22(ArrowUpIcon, { size: "xs" }),
1441
1495
  down: /* @__PURE__ */ jsx22(ArrowDownIcon, { size: "xs" }),
@@ -1463,7 +1517,7 @@ function Stat({
1463
1517
  "data-size": size,
1464
1518
  ...rest
1465
1519
  },
1466
- /* @__PURE__ */ jsxs19(Fragment4, { children: [
1520
+ /* @__PURE__ */ jsxs19(Fragment5, { children: [
1467
1521
  /* @__PURE__ */ jsx22("div", { className: "sc-stat__label", children: label }),
1468
1522
  icon ? /* @__PURE__ */ jsx22("span", { className: "sc-stat__icon", "aria-hidden": "true", children: icon }) : null,
1469
1523
  /* @__PURE__ */ jsx22("div", { className: "sc-stat__value", children: value }),
@@ -1480,6 +1534,206 @@ function Stat({
1480
1534
  );
1481
1535
  }
1482
1536
 
1537
+ // src/components/Chip/Chip.tsx
1538
+ import { Fragment as Fragment6, jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
1539
+ function Chip({
1540
+ children,
1541
+ icon,
1542
+ tone = "neutral",
1543
+ size = "md",
1544
+ selected = false,
1545
+ onClick,
1546
+ onRemove,
1547
+ removeLabel,
1548
+ disabled = false,
1549
+ className,
1550
+ ...rest
1551
+ }) {
1552
+ const interactive = onClick !== void 0;
1553
+ const removeName = removeLabel ?? (typeof children === "string" ? `Remove ${children}` : "Remove");
1554
+ const handleRemoveKey = (event) => {
1555
+ if (onRemove && !disabled && (event.key === "Backspace" || event.key === "Delete")) {
1556
+ event.preventDefault();
1557
+ onRemove();
1558
+ }
1559
+ };
1560
+ const shared = {
1561
+ className: cx("sc-chip", className),
1562
+ "data-tone": tone,
1563
+ "data-size": size,
1564
+ "data-selected": selected || void 0,
1565
+ "data-removable": onRemove ? "" : void 0,
1566
+ "data-disabled": disabled || void 0
1567
+ };
1568
+ const body = /* @__PURE__ */ jsxs20(Fragment6, { children: [
1569
+ icon ? /* @__PURE__ */ jsx23("span", { className: "sc-chip__icon", "aria-hidden": "true", children: icon }) : null,
1570
+ /* @__PURE__ */ jsx23("span", { className: "sc-chip__label", children })
1571
+ ] });
1572
+ const remove = onRemove ? /* @__PURE__ */ jsx23(
1573
+ "button",
1574
+ {
1575
+ type: "button",
1576
+ className: "sc-chip__remove",
1577
+ "aria-label": removeName,
1578
+ disabled,
1579
+ onClick: (event) => {
1580
+ event.stopPropagation();
1581
+ onRemove();
1582
+ },
1583
+ onKeyDown: handleRemoveKey,
1584
+ children: /* @__PURE__ */ jsx23(XIcon, { size: "xs" })
1585
+ }
1586
+ ) : null;
1587
+ if (interactive) {
1588
+ return /* @__PURE__ */ jsxs20("span", { ...shared, ...rest, children: [
1589
+ /* @__PURE__ */ jsx23(
1590
+ "button",
1591
+ {
1592
+ type: "button",
1593
+ className: "sc-chip__action",
1594
+ "aria-pressed": selected,
1595
+ disabled,
1596
+ onClick,
1597
+ onKeyDown: handleRemoveKey,
1598
+ children: body
1599
+ }
1600
+ ),
1601
+ remove
1602
+ ] });
1603
+ }
1604
+ return /* @__PURE__ */ jsxs20("span", { ...shared, ...rest, children: [
1605
+ body,
1606
+ remove
1607
+ ] });
1608
+ }
1609
+
1610
+ // src/components/Disclosure/Disclosure.tsx
1611
+ import {
1612
+ useEffect,
1613
+ useRef,
1614
+ useState as useState3
1615
+ } from "react";
1616
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
1617
+ function Disclosure({
1618
+ summary,
1619
+ summaryOpen,
1620
+ open,
1621
+ defaultOpen = false,
1622
+ onOpenChange,
1623
+ previewLines,
1624
+ summaryPosition,
1625
+ className,
1626
+ style,
1627
+ children,
1628
+ ref,
1629
+ ...rest
1630
+ }) {
1631
+ const controlled = open !== void 0;
1632
+ const [internal, setInternal] = useState3(defaultOpen);
1633
+ const isOpen = controlled ? open : internal;
1634
+ const inner = useRef(null);
1635
+ useEffect(() => {
1636
+ if (controlled && inner.current && inner.current.open !== open) inner.current.open = open;
1637
+ });
1638
+ const onToggle = (event) => {
1639
+ const next = event.currentTarget.open;
1640
+ if (next === isOpen) return;
1641
+ if (!controlled) setInternal(next);
1642
+ onOpenChange?.(next);
1643
+ };
1644
+ const position = summaryPosition ?? (previewLines ? "end" : "start");
1645
+ return /* @__PURE__ */ jsxs21(
1646
+ "details",
1647
+ {
1648
+ ref: (node) => {
1649
+ inner.current = node;
1650
+ if (typeof ref === "function") ref(node);
1651
+ else if (ref) ref.current = node;
1652
+ },
1653
+ className: cx("sc-disclosure", className),
1654
+ open: isOpen,
1655
+ onToggle,
1656
+ "data-summary-position": position,
1657
+ "data-preview": previewLines ? "" : void 0,
1658
+ style: previewLines ? { ...style, "--_lines": previewLines } : style,
1659
+ ...rest,
1660
+ children: [
1661
+ /* @__PURE__ */ jsxs21("summary", { className: "sc-disclosure__summary", children: [
1662
+ /* @__PURE__ */ jsx24(ChevronDownIcon, { className: "sc-disclosure__chevron" }),
1663
+ /* @__PURE__ */ jsx24("span", { className: "sc-disclosure__summary-text", children: isOpen && summaryOpen != null ? summaryOpen : summary })
1664
+ ] }),
1665
+ /* @__PURE__ */ jsx24("div", { className: "sc-disclosure__content", children })
1666
+ ]
1667
+ }
1668
+ );
1669
+ }
1670
+
1671
+ // src/components/EmptyState/EmptyState.tsx
1672
+ import { createElement as createElement6 } from "react";
1673
+ import { jsx as jsx25 } from "react/jsx-runtime";
1674
+ function EmptyState({
1675
+ title,
1676
+ description,
1677
+ icon,
1678
+ children,
1679
+ size = "md",
1680
+ as = "div",
1681
+ className,
1682
+ ...rest
1683
+ }) {
1684
+ return createElement6(
1685
+ as,
1686
+ { className: cx("sc-empty-state", className), "data-size": size, ...rest },
1687
+ icon ? /* @__PURE__ */ jsx25("span", { className: "sc-empty-state__icon", "aria-hidden": "true", children: icon }) : null,
1688
+ /* @__PURE__ */ jsx25("p", { className: "sc-empty-state__title", children: title }),
1689
+ description != null ? /* @__PURE__ */ jsx25("p", { className: "sc-empty-state__description", children: description }) : null,
1690
+ children != null ? /* @__PURE__ */ jsx25("div", { className: "sc-empty-state__actions", children }) : null
1691
+ );
1692
+ }
1693
+
1694
+ // src/components/Skeleton/Skeleton.tsx
1695
+ import { jsx as jsx26 } from "react/jsx-runtime";
1696
+ function Skeleton({
1697
+ variant = "text",
1698
+ width,
1699
+ height,
1700
+ lines = 1,
1701
+ still = false,
1702
+ className,
1703
+ style,
1704
+ ...rest
1705
+ }) {
1706
+ const size = {
1707
+ ...style,
1708
+ ...width !== void 0 ? { inlineSize: width } : {},
1709
+ ...height !== void 0 ? { blockSize: height } : {}
1710
+ };
1711
+ if (variant === "text" && lines > 1) {
1712
+ return /* @__PURE__ */ jsx26("span", { className: cx("sc-skeleton-lines", className), "aria-hidden": "true", style, ...rest, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx26(
1713
+ "span",
1714
+ {
1715
+ className: "sc-skeleton",
1716
+ "data-variant": "text",
1717
+ "data-still": still || void 0,
1718
+ "data-last": i === lines - 1 || void 0,
1719
+ style: width !== void 0 ? { inlineSize: width } : void 0
1720
+ },
1721
+ i
1722
+ )) });
1723
+ }
1724
+ return /* @__PURE__ */ jsx26(
1725
+ "span",
1726
+ {
1727
+ className: cx("sc-skeleton", className),
1728
+ "data-variant": variant,
1729
+ "data-still": still || void 0,
1730
+ "aria-hidden": "true",
1731
+ style: size,
1732
+ ...rest
1733
+ }
1734
+ );
1735
+ }
1736
+
1483
1737
  // src/index.ts
1484
1738
  var version = "0.1.1";
1485
1739
  export {
@@ -1501,14 +1755,17 @@ export {
1501
1755
  ChevronLeftIcon,
1502
1756
  ChevronRightIcon,
1503
1757
  ChevronUpIcon,
1758
+ Chip,
1504
1759
  CircleCheckIcon,
1505
1760
  CircleXIcon,
1506
1761
  ClockIcon,
1507
1762
  CopyIcon,
1508
1763
  Dialog,
1764
+ Disclosure,
1509
1765
  DocumentIcon,
1510
1766
  DownloadIcon,
1511
1767
  EditIcon,
1768
+ EmptyState,
1512
1769
  ExternalLinkIcon,
1513
1770
  EyeIcon,
1514
1771
  FilterIcon,
@@ -1538,6 +1795,7 @@ export {
1538
1795
  SearchIcon,
1539
1796
  Select,
1540
1797
  SettingsIcon,
1798
+ Skeleton,
1541
1799
  Spinner,
1542
1800
  Stack,
1543
1801
  StarIcon,