@salemcobalt/ui 0.2.0-rc.3 → 0.2.0-rc.5

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
@@ -457,7 +457,7 @@ function Root({ dismissible = true, onOpenChange, open, defaultOpen, children })
457
457
  );
458
458
  }
459
459
  var Trigger = BaseDialog.Trigger;
460
- function Content({ size = "md", className, children, ...rest }) {
460
+ function Content({ size = "md", variant = "dialog", className, children, ...rest }) {
461
461
  return /* @__PURE__ */ jsxs5(BaseDialog.Portal, { children: [
462
462
  /* @__PURE__ */ jsx6(BaseDialog.Backdrop, { className: "sc-dialog__backdrop" }),
463
463
  /* @__PURE__ */ jsx6(
@@ -465,6 +465,7 @@ function Content({ size = "md", className, children, ...rest }) {
465
465
  {
466
466
  className: cx("sc-dialog__popup", className),
467
467
  "data-size": size,
468
+ "data-variant": variant,
468
469
  "aria-modal": "true",
469
470
  ...rest,
470
471
  children
@@ -545,6 +546,9 @@ var iconNames = [
545
546
  "x"
546
547
  ];
547
548
 
549
+ // src/components/IconButton/IconButton.tsx
550
+ import { useRender as useRender2 } from "@base-ui/react/use-render";
551
+
548
552
  // src/components/Tooltip/Tooltip.tsx
549
553
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
550
554
  import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
@@ -582,7 +586,7 @@ var Provider = BaseTooltip.Provider;
582
586
  var Tooltip = Object.assign(TooltipBase, { Provider });
583
587
 
584
588
  // src/components/IconButton/IconButton.tsx
585
- 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";
586
590
  function IconButton({
587
591
  label,
588
592
  children,
@@ -592,9 +596,11 @@ function IconButton({
592
596
  tooltipSide = "top",
593
597
  round = false,
594
598
  loading = false,
595
- type = "button",
599
+ type,
596
600
  className,
597
601
  onClick,
602
+ render,
603
+ ref,
598
604
  ...rest
599
605
  }) {
600
606
  const handleClick = (event) => {
@@ -604,10 +610,13 @@ function IconButton({
604
610
  }
605
611
  onClick?.(event);
606
612
  };
607
- const button = /* @__PURE__ */ jsxs7(
608
- "button",
609
- {
610
- 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",
611
620
  className: cx("sc-button", "sc-icon-button", className),
612
621
  "data-variant": variant,
613
622
  "data-size": size,
@@ -617,19 +626,19 @@ function IconButton({
617
626
  "aria-label": label,
618
627
  onClick: handleClick,
619
628
  ...rest,
620
- children: [
629
+ children: /* @__PURE__ */ jsxs7(Fragment2, { children: [
621
630
  /* @__PURE__ */ jsx8("span", { className: "sc-button__icon", "aria-hidden": "true", children }),
622
631
  loading ? /* @__PURE__ */ jsx8("span", { className: "sc-button__spinner", "aria-hidden": "true" }) : null
623
- ]
632
+ ] })
624
633
  }
625
- );
634
+ });
626
635
  if (!tooltip) return button;
627
636
  return /* @__PURE__ */ jsx8(Tooltip, { content: tooltip === true ? label : tooltip, side: tooltipSide, children: button });
628
637
  }
629
638
 
630
639
  // src/components/Menu/Menu.tsx
631
640
  import { Menu as BaseMenu } from "@base-ui/react/menu";
632
- 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";
633
642
  function Root2({ open, defaultOpen, onOpenChange, disabled, modal = true, children }) {
634
643
  return /* @__PURE__ */ jsx9(
635
644
  BaseMenu.Root,
@@ -669,7 +678,7 @@ function ItemBody({
669
678
  trailing,
670
679
  children
671
680
  }) {
672
- return /* @__PURE__ */ jsxs8(Fragment2, { children: [
681
+ return /* @__PURE__ */ jsxs8(Fragment3, { children: [
673
682
  /* @__PURE__ */ jsx9("span", { className: "sc-menu__icon", "aria-hidden": "true", children: icon }),
674
683
  /* @__PURE__ */ jsx9("span", { className: "sc-menu__label", children }),
675
684
  trailing !== void 0 ? /* @__PURE__ */ jsx9("span", { className: "sc-menu__trailing", children: trailing }) : null
@@ -856,9 +865,14 @@ function Textarea({
856
865
  className,
857
866
  rows = 3,
858
867
  resize = "vertical",
868
+ variant = "default",
859
869
  onValueChange,
870
+ spellCheck,
871
+ autoCorrect,
872
+ autoCapitalize,
860
873
  ...rest
861
874
  }) {
875
+ const code = variant === "code";
862
876
  return /* @__PURE__ */ jsx12(
863
877
  FieldShell,
864
878
  {
@@ -874,9 +888,19 @@ function Textarea({
874
888
  children: /* @__PURE__ */ jsx12(
875
889
  Field3.Control,
876
890
  {
877
- 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
+ ),
878
901
  className: "sc-input sc-textarea",
879
902
  "data-resize": resize,
903
+ "data-variant": code ? "code" : void 0,
880
904
  required,
881
905
  onValueChange: onValueChange ? (value) => onValueChange(value) : void 0
882
906
  }
@@ -887,6 +911,7 @@ function Textarea({
887
911
 
888
912
  // src/components/Select/Select.tsx
889
913
  import { Select as BaseSelect } from "@base-ui/react/select";
914
+ import { useState } from "react";
890
915
  import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
891
916
  function isGroup(entry) {
892
917
  return "options" in entry;
@@ -913,11 +938,27 @@ function Select({
913
938
  defaultValue,
914
939
  onValueChange,
915
940
  placeholder = "Choose\u2026",
941
+ clearable = false,
942
+ clearLabel = "Clear",
916
943
  readOnly,
917
944
  fullWidth = false,
918
945
  id
919
946
  }) {
920
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
+ };
921
962
  return /* @__PURE__ */ jsx13(
922
963
  FieldShell,
923
964
  {
@@ -935,26 +976,39 @@ function Select({
935
976
  BaseSelect.Root,
936
977
  {
937
978
  items,
938
- value,
939
- defaultValue,
940
- onValueChange: onValueChange ? (next) => onValueChange(next) : void 0,
979
+ value: current,
980
+ onValueChange: (next) => setValue(next),
941
981
  disabled,
942
982
  required,
943
983
  readOnly,
944
984
  children: [
945
- /* @__PURE__ */ jsxs11(
946
- BaseSelect.Trigger,
947
- {
948
- id,
949
- className: "sc-select",
950
- "data-size": size,
951
- "data-full-width": fullWidth || void 0,
952
- children: [
953
- /* @__PURE__ */ jsx13(BaseSelect.Value, { className: "sc-select__value", placeholder }),
954
- /* @__PURE__ */ jsx13(BaseSelect.Icon, { className: "sc-select__icon", children: /* @__PURE__ */ jsx13(ChevronDownIcon, {}) })
955
- ]
956
- }
957
- ),
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
+ ] }),
958
1012
  /* @__PURE__ */ jsx13(BaseSelect.Portal, { children: /* @__PURE__ */ jsx13(
959
1013
  BaseSelect.Positioner,
960
1014
  {
@@ -1054,7 +1108,7 @@ function Switch({
1054
1108
 
1055
1109
  // src/components/Tabs/Tabs.tsx
1056
1110
  import { Tabs as BaseTabs } from "@base-ui/react/tabs";
1057
- 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";
1058
1112
  function Root3({ className, onValueChange, ...rest }) {
1059
1113
  return /* @__PURE__ */ jsx16(
1060
1114
  BaseTabs.Root,
@@ -1075,7 +1129,7 @@ function Tab({ icon, count, className, children, ...rest }) {
1075
1129
  return /* @__PURE__ */ jsxs14(BaseTabs.Tab, { className: cx("sc-tabs__tab", className), ...rest, children: [
1076
1130
  icon ? /* @__PURE__ */ jsx16("span", { className: "sc-tabs__icon", "aria-hidden": "true", children: icon }) : null,
1077
1131
  /* @__PURE__ */ jsx16("span", { className: "sc-tabs__label", children }),
1078
- count != null ? /* @__PURE__ */ jsxs14(Fragment3, { children: [
1132
+ count != null ? /* @__PURE__ */ jsxs14(Fragment4, { children: [
1079
1133
  " ",
1080
1134
  /* @__PURE__ */ jsx16("span", { className: "sc-tabs__count", children: count })
1081
1135
  ] }) : null
@@ -1107,13 +1161,14 @@ function Separator2({ className, ...rest }) {
1107
1161
  return /* @__PURE__ */ jsx17(BaseToolbar.Separator, { className: cx("sc-toolbar__separator", className), ...rest });
1108
1162
  }
1109
1163
  var Button2 = BaseToolbar.Button;
1164
+ var Link = BaseToolbar.Link;
1110
1165
  function Spacer({ className }) {
1111
1166
  return /* @__PURE__ */ jsx17("div", { className: cx("sc-toolbar__spacer", className), "aria-hidden": "true" });
1112
1167
  }
1113
- var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Spacer };
1168
+ var Toolbar = { Root: Root4, Group: Group2, Separator: Separator2, Button: Button2, Link, Spacer };
1114
1169
 
1115
1170
  // src/components/Banner/Banner.tsx
1116
- import { useState } from "react";
1171
+ import { useState as useState2 } from "react";
1117
1172
  import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1118
1173
  var toneIcons = {
1119
1174
  info: /* @__PURE__ */ jsx18(InfoIcon, {}),
@@ -1135,7 +1190,7 @@ function Banner({
1135
1190
  children,
1136
1191
  ...rest
1137
1192
  }) {
1138
- const [dismissed, setDismissed] = useState(false);
1193
+ const [dismissed, setDismissed] = useState2(false);
1139
1194
  const visible = open ?? !dismissed;
1140
1195
  if (!visible) return null;
1141
1196
  const glyph = icon === false ? null : icon ?? toneIcons[tone];
@@ -1434,7 +1489,7 @@ var Table = { Root: Root5, Caption, Head, Body: Body2, Foot, Row, Header, Cell }
1434
1489
 
1435
1490
  // src/components/Stat/Stat.tsx
1436
1491
  import { createElement as createElement5 } from "react";
1437
- 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";
1438
1493
  var trendIcons = {
1439
1494
  up: /* @__PURE__ */ jsx22(ArrowUpIcon, { size: "xs" }),
1440
1495
  down: /* @__PURE__ */ jsx22(ArrowDownIcon, { size: "xs" }),
@@ -1462,7 +1517,7 @@ function Stat({
1462
1517
  "data-size": size,
1463
1518
  ...rest
1464
1519
  },
1465
- /* @__PURE__ */ jsxs19(Fragment4, { children: [
1520
+ /* @__PURE__ */ jsxs19(Fragment5, { children: [
1466
1521
  /* @__PURE__ */ jsx22("div", { className: "sc-stat__label", children: label }),
1467
1522
  icon ? /* @__PURE__ */ jsx22("span", { className: "sc-stat__icon", "aria-hidden": "true", children: icon }) : null,
1468
1523
  /* @__PURE__ */ jsx22("div", { className: "sc-stat__value", children: value }),
@@ -1479,6 +1534,206 @@ function Stat({
1479
1534
  );
1480
1535
  }
1481
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
+
1482
1737
  // src/index.ts
1483
1738
  var version = "0.1.1";
1484
1739
  export {
@@ -1500,14 +1755,17 @@ export {
1500
1755
  ChevronLeftIcon,
1501
1756
  ChevronRightIcon,
1502
1757
  ChevronUpIcon,
1758
+ Chip,
1503
1759
  CircleCheckIcon,
1504
1760
  CircleXIcon,
1505
1761
  ClockIcon,
1506
1762
  CopyIcon,
1507
1763
  Dialog,
1764
+ Disclosure,
1508
1765
  DocumentIcon,
1509
1766
  DownloadIcon,
1510
1767
  EditIcon,
1768
+ EmptyState,
1511
1769
  ExternalLinkIcon,
1512
1770
  EyeIcon,
1513
1771
  FilterIcon,
@@ -1537,6 +1795,7 @@ export {
1537
1795
  SearchIcon,
1538
1796
  Select,
1539
1797
  SettingsIcon,
1798
+ Skeleton,
1540
1799
  Spinner,
1541
1800
  Stack,
1542
1801
  StarIcon,