@olundot/ui 0.20.2 → 0.21.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # @olundot/ui
2
2
 
3
+ ## 0.21.1
4
+
5
+ ### Patch Changes
6
+
7
+ - dcadbb9: ModeToggle과 Tabs `contained`의 선택 칸에 테두리가 생기고, 어둠 테마에서 선택 칸이 홈보다 밝아집니다.
8
+
9
+ ## 0.21.0
10
+
11
+ ### Minor Changes
12
+
13
+ - e5aadba: 호환성을 깨는 변경이다. `BulkActionBar`의 `placement="inline"`, `compactSummary`, `trailing`을 지웠다. 세 가지 모두 0.20에서 사용 중단으로 표시한 것이다.
14
+
15
+ - `placement`는 `"floating"`만 받는다. 넘기던 곳에서는 `placement`를 지운다.
16
+ - `compactSummary`와 `trailing`은 `inline`에서만 쓰였다. 넘기던 곳에서는 지운다.
17
+ - `DataTable`의 가상 목록 머리가 `inline` 바 아래로 내려가던 `top-[40px]` 보정을 지웠다.
18
+ - `idleContent`, `emptyHint`, `DataTable`의 `announceSelection`은 그대로다.
19
+
20
+ ### Patch Changes
21
+
22
+ - 77acbcb: `AlertDialog`와 `ConfirmDialog`는 `description`과 본문이 모두 없으면 `aria-describedby`를 붙이지 않는다. 전에는 화면에 없는 요소의 id를 가리켰다. 제목을 설명으로 다시 쓰지 않으며, Radix의 개발 경고는 그대로 난다. 설명이나 본문이 있으면 지금처럼 그 요소를 가리킨다.
23
+ - 77acbcb: `AlertDialog`(`ConfirmDialog` 포함)와 구조형 `Dialog` 폼 모드는 `open`이 `false`가 되면 `onConfirm`·`onSubmit`이 잡고 있던 실행 중 상태를 푼다. 소비자가 준 `loading`이 `true`면 그대로 잠긴다. 전에는 `onConfirm`·`onSubmit`이 끝날 때까지 남아, 그사이 다시 연 창의 확인 버튼이 로딩으로 돌고 취소·Escape가 막혔다가 앞 실행이 끝나면 창이 닫혔다.
24
+
25
+ - 닫히기 전에 시작한 실행은 취소하지 않고 끝까지 간다. 끝나도 다시 연 창을 닫지 않고, 실행 중 상태를 풀지 않으며, 실패를 `onError`로 넘기지 않는다. `onError`가 없으면 실패는 지금처럼 호출자에게 전파된다.
26
+ - 닫힌 동안에는 실행하지 않는다. 닫히는 애니메이션 중 남은 확인·제출 버튼을 눌러도 `onConfirm`·`onSubmit`을 부르지 않는다.
27
+ - 같은 열림 안에서 한 번만 실행, 실행 중 닫기 막기, 성공하면 한 번 닫기는 그대로다.
28
+ - 닫았다 다시 연 창에서 같은 요청을 다시 보내는 중복은 막지 않는다. 핸들러와 서버가 막는다.
29
+
3
30
  ## 0.20.2
4
31
 
5
32
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1134,9 +1134,9 @@ interface DataTableBaseProps<T> extends Omit<React.HTMLAttributes<HTMLDivElement
1134
1134
  selectionUnit?: string;
1135
1135
  /**
1136
1136
  * `false` drops the built-in screen-reader selection message — when a
1137
- * `BulkActionBar placement="inline"` already announces the count (it is a status
1138
- * region), or when the real selection includes rows that are not loaded (the
1139
- * built-in message only counts loaded rows). Default `true`.
1137
+ * `BulkActionBar` already announces the count (it is a status region), or when the
1138
+ * real selection includes rows that are not loaded (the built-in message only
1139
+ * counts loaded rows). Default `true`.
1140
1140
  */
1141
1141
  announceSelection?: boolean;
1142
1142
  activeRowId?: string;
@@ -1294,42 +1294,24 @@ interface BulkActionBarBaseProps extends React.HTMLAttributes<HTMLDivElement> {
1294
1294
  /** Count unit — `12명 선택됨`. Defaults to `개`. */
1295
1295
  unit?: string;
1296
1296
  /**
1297
- * Under the count in the floating card, next to it inline — e.g. an "이 조건의 3,214명
1298
- * 모두 선택" link or a cap notice. The card wraps it at full width, never clips it.
1297
+ * Under the count — e.g. an "이 조건의 3,214명 모두 선택" link or a cap notice. The card
1298
+ * wraps it at full width, never clips it.
1299
1299
  */
1300
1300
  summary?: React.ReactNode;
1301
- /**
1302
- * Inline only: a shorter `summary` (e.g. "모두 선택") swapped in when the band is too
1303
- * narrow to show `summary` on one line. Without it, `summary` is clipped, never wrapped.
1304
- *
1305
- * @deprecated Only `placement="inline"` uses it; removed together with `inline` in the next minor.
1306
- */
1307
- compactSummary?: React.ReactNode;
1301
+ /** Removed in 0.21 with `placement="inline"`. */
1302
+ compactSummary?: never;
1303
+ /** Removed in 0.21 with `placement="inline"`. */
1304
+ trailing?: never;
1308
1305
  /**
1309
1306
  * Shown instead of the bar while nothing is selected (e.g. `100 / 3,214명`).
1310
1307
  * Takes precedence over `emptyHint`; with neither, the bar hides at count 0.
1311
1308
  */
1312
1309
  idleContent?: React.ReactNode;
1313
1310
  }
1314
- type BulkActionBarProps = BulkActionBarBaseProps & ({
1311
+ interface BulkActionBarProps extends BulkActionBarBaseProps {
1315
1312
  /** `floating` (default) — card stuck to the bottom of the list. */
1316
1313
  placement?: "floating";
1317
- /** Not taken by the floating card: edit-mode controls go at the right end of the toolbar. */
1318
- trailing?: never;
1319
- } | {
1320
- /**
1321
- * `inline` — full-width band stuck to the top, placed where the status line sits
1322
- * under the toolbar. Render it BEFORE the list so it comes first in tab order.
1323
- * Deprecated: `inline` is removed in the next minor.
1324
- */
1325
- placement: "inline";
1326
- /**
1327
- * Inline only: after the clear (✕) button — e.g. an edit-mode "완료" button. On the
1328
- * idle line it sits at the right end, outside the `role="status"` region, so it is
1329
- * not re-read whenever `idleContent` changes.
1330
- */
1331
- trailing?: React.ReactNode;
1332
- });
1314
+ }
1333
1315
  /**
1334
1316
  * OLUN BulkActionBar — multi-select table/list actions.
1335
1317
  *
@@ -1339,13 +1321,7 @@ type BulkActionBarProps = BulkActionBarBaseProps & ({
1339
1321
  * they do not fit. `variant: "destructive"` is outline danger. The card is
1340
1322
  * min(360px, its slot − 32px) wide; while it is near the viewport bottom the document root
1341
1323
  * carries `--olun-bulk-bar-offset` (viewport bottom → card top) for toasts to clear it.
1342
- * DOM order stays count → actions → ✕. It takes no `trailing`.
1343
- *
1344
- * placement="inline" (deprecated) is a top-sticky band that replaces the status
1345
- * line under the toolbar, so it comes before the rows in tab order. The band and
1346
- * the idle line are one 40px line: a long `summary` is clipped or swapped for
1347
- * `compactSummary`, never wrapped. Its actions are borderless text/icon buttons
1348
- * between hairline dividers; `trailing` follows the clear button.
1324
+ * DOM order stays count → actions → ✕.
1349
1325
  *
1350
1326
  * `unit` sets the count unit, `idleContent` shows while nothing is selected.
1351
1327
  *
@@ -1356,7 +1332,7 @@ type BulkActionBarProps = BulkActionBarBaseProps & ({
1356
1332
  * { key: "del", label: "삭제", variant: "destructive", onClick: confirmDelete },
1357
1333
  * ]} />
1358
1334
  */
1359
- declare function BulkActionBar({ count, actions, onClear, emptyHint, placement, unit, summary, compactSummary, idleContent, trailing, className, style, ...props }: BulkActionBarProps): react_jsx_runtime.JSX.Element | null;
1335
+ declare function BulkActionBar({ count, actions, onClear, emptyHint, placement: _placement, compactSummary: _compactSummary, trailing: _trailing, unit, summary, idleContent, className, style, ...props }: BulkActionBarProps): react_jsx_runtime.JSX.Element | null;
1360
1336
 
1361
1337
  interface ConfirmDialogProps {
1362
1338
  open: boolean;
package/dist/index.js CHANGED
@@ -3228,7 +3228,7 @@ var tabsTriggerVariants = cva9(
3228
3228
  variants: {
3229
3229
  variant: {
3230
3230
  line: "",
3231
- contained: "rounded-[var(--radius-sm)] border border-transparent px-[var(--space-3)] data-[state=active]:border-[var(--border-strong)] data-[state=active]:bg-[var(--action-selected)] data-[state=active]:after:hidden"
3231
+ contained: "rounded-[var(--radius-sm)] border border-transparent px-[var(--space-3)] data-[state=active]:border-[var(--text-tertiary)] data-[state=active]:bg-[var(--fill-on-inset)] data-[state=active]:after:hidden"
3232
3232
  },
3233
3233
  orientation: {
3234
3234
  horizontal: "",
@@ -3800,6 +3800,7 @@ import { Dialog as DialogPrimitive3 } from "radix-ui";
3800
3800
  // src/lib/use-overlay-action.ts
3801
3801
  import * as React22 from "react";
3802
3802
  function useOverlayAction({
3803
+ open,
3803
3804
  action,
3804
3805
  onOpenChange,
3805
3806
  loading = false,
@@ -3808,7 +3809,14 @@ function useOverlayAction({
3808
3809
  }) {
3809
3810
  const [pending, setPending] = React22.useState(false);
3810
3811
  const busyRef = React22.useRef(false);
3812
+ const runIdRef = React22.useRef(0);
3811
3813
  const isBusy = loading || pending;
3814
+ React22.useEffect(() => {
3815
+ if (open) return;
3816
+ runIdRef.current += 1;
3817
+ busyRef.current = false;
3818
+ setPending(false);
3819
+ }, [open]);
3812
3820
  const guardOpenChange = React22.useCallback(
3813
3821
  (nextOpen) => {
3814
3822
  if (!nextOpen && isBusy) {
@@ -3819,22 +3827,25 @@ function useOverlayAction({
3819
3827
  [isBusy, onOpenChange]
3820
3828
  );
3821
3829
  const run = React22.useCallback(async () => {
3822
- if (busyRef.current || loading || disabled) {
3830
+ if (!open || busyRef.current || loading || disabled) {
3823
3831
  return;
3824
3832
  }
3833
+ const runId = ++runIdRef.current;
3825
3834
  busyRef.current = true;
3826
3835
  setPending(true);
3827
3836
  try {
3828
3837
  await action();
3829
- onOpenChange(false);
3838
+ if (runId === runIdRef.current) onOpenChange(false);
3830
3839
  } catch (error) {
3831
3840
  if (!onError) throw error;
3832
- onError(error);
3841
+ if (runId === runIdRef.current) onError(error);
3833
3842
  } finally {
3834
- busyRef.current = false;
3835
- setPending(false);
3843
+ if (runId === runIdRef.current) {
3844
+ busyRef.current = false;
3845
+ setPending(false);
3846
+ }
3836
3847
  }
3837
- }, [action, disabled, loading, onError, onOpenChange]);
3848
+ }, [action, disabled, loading, onError, onOpenChange, open]);
3838
3849
  return { isBusy, run, guardOpenChange };
3839
3850
  }
3840
3851
 
@@ -5019,6 +5030,7 @@ function StructuredDialog({
5019
5030
  const policy = OVERLAY_POLICY.dialog;
5020
5031
  const formMode = onSubmit !== void 0;
5021
5032
  const { isBusy, run, guardOpenChange } = useOverlayAction({
5033
+ open,
5022
5034
  action: onSubmit ?? noAction,
5023
5035
  onOpenChange,
5024
5036
  loading: formMode && loading,
@@ -5326,6 +5338,7 @@ function AlertDialogFrame({
5326
5338
  className: overlayBoxClassName("alert"),
5327
5339
  onOpenAutoFocus,
5328
5340
  onCloseAutoFocus: returnFocus.onCloseAutoFocus,
5341
+ ...description == null && children == null && { "aria-describedby": void 0 },
5329
5342
  children: [
5330
5343
  /* @__PURE__ */ jsx28(OverlayHeader, { kind: "alert", title, description }),
5331
5344
  children != null ? description != null ? /* @__PURE__ */ jsx28(OverlayBody, { kind: "alert", children }) : /* @__PURE__ */ jsx28(AlertDialogPrimitive2.Description, { asChild: true, children: /* @__PURE__ */ jsx28(OverlayBody, { kind: "alert", children }) }) : null,
@@ -5352,6 +5365,7 @@ function AlertDialog({
5352
5365
  acknowledgeLabel = "\uD655\uC778"
5353
5366
  }) {
5354
5367
  const { isBusy, run, guardOpenChange } = useOverlayAction({
5368
+ open,
5355
5369
  action: onConfirm ?? noop,
5356
5370
  onOpenChange,
5357
5371
  loading,
@@ -8532,10 +8546,8 @@ function DataTableInner({
8532
8546
  role: "row",
8533
8547
  className: cn(
8534
8548
  "grid min-h-[40px] items-center bg-[var(--bg-raised)] text-[12px] font-semibold leading-snug text-text-tertiary",
8535
- // Virtual lists are long: the header sticks inside the scroll container,
8536
- // below an inline BulkActionBar band (40px, --z-sticky) rendered before
8537
- // the table — band on top, header under it, rows beneath both.
8538
- isVirtual && "sticky top-0 z-[2] [[data-slot=bulk-action-bar][data-placement=inline]:not([data-state=idle])~[data-slot=data-table]_&]:top-[40px]"
8549
+ // Virtual lists are long: the header sticks inside the scroll container.
8550
+ isVirtual && "sticky top-0 z-[2]"
8539
8551
  ),
8540
8552
  style: { gridTemplateColumns },
8541
8553
  children: [
@@ -8677,51 +8689,6 @@ DataTable.displayName = "DataTable";
8677
8689
  import * as React36 from "react";
8678
8690
  import { X as X4 } from "lucide-react";
8679
8691
  import { jsx as jsx39, jsxs as jsxs35 } from "react/jsx-runtime";
8680
- function ActionButton({ action }) {
8681
- const danger = action.variant === "destructive";
8682
- const off = action.disabled;
8683
- const Icon = action.icon;
8684
- return /* @__PURE__ */ jsxs35(
8685
- "button",
8686
- {
8687
- type: "button",
8688
- "data-slot": "bulk-action-bar-action",
8689
- "data-variant": action.variant ?? "default",
8690
- disabled: off,
8691
- title: action.title,
8692
- onClick: action.onClick,
8693
- className: cn(
8694
- "border-0 bg-transparent outline-none transition-[background-color,box-shadow,color] motion-reduce:transition-none",
8695
- "focus-visible:shadow-[0_0_0_2px_var(--focus-ring)]",
8696
- off ? "cursor-not-allowed text-text-disabled" : danger ? "cursor-pointer text-[var(--error)] hover:bg-[var(--error-bg)]" : "cursor-pointer text-text-secondary hover:bg-[var(--action-hover)] hover:text-foreground"
8697
- ),
8698
- style: {
8699
- display: "inline-flex",
8700
- alignItems: "center",
8701
- gap: 6,
8702
- height: 30,
8703
- padding: "0 10px",
8704
- borderRadius: "var(--radius-md)",
8705
- fontFamily: "var(--font-sans)",
8706
- fontSize: 13,
8707
- fontWeight: 500,
8708
- whiteSpace: "nowrap"
8709
- },
8710
- children: [
8711
- Icon ? /* @__PURE__ */ jsx39(
8712
- Icon,
8713
- {
8714
- "aria-hidden": "true",
8715
- "data-slot": "bulk-action-bar-action-icon",
8716
- size: 16,
8717
- strokeWidth: 1.75
8718
- }
8719
- ) : null,
8720
- action.label
8721
- ]
8722
- }
8723
- );
8724
- }
8725
8692
  function CardActionButton({ action }) {
8726
8693
  const Icon = action.icon;
8727
8694
  return /* @__PURE__ */ jsxs35(
@@ -8751,52 +8718,8 @@ function CardActionButton({ action }) {
8751
8718
  }
8752
8719
  );
8753
8720
  }
8754
- function Divider() {
8755
- return /* @__PURE__ */ jsx39(
8756
- "span",
8757
- {
8758
- "aria-hidden": "true",
8759
- "data-slot": "bulk-action-bar-divider",
8760
- style: {
8761
- width: 1,
8762
- height: 18,
8763
- flexShrink: 0,
8764
- background: "var(--border-subtle)"
8765
- }
8766
- }
8767
- );
8768
- }
8769
- function ClearButton({ onClear }) {
8770
- return /* @__PURE__ */ jsx39(
8771
- "button",
8772
- {
8773
- type: "button",
8774
- "aria-label": "\uC120\uD0DD \uD574\uC81C",
8775
- "data-slot": "bulk-action-bar-clear",
8776
- onClick: onClear,
8777
- className: cn(
8778
- "cursor-pointer border-0 bg-transparent text-text-secondary outline-none",
8779
- "transition-[background-color,box-shadow,color] motion-reduce:transition-none",
8780
- "hover:bg-[var(--action-hover)] hover:text-foreground",
8781
- "focus-visible:shadow-[0_0_0_2px_var(--focus-ring)]"
8782
- ),
8783
- style: {
8784
- display: "inline-flex",
8785
- width: 32,
8786
- height: 32,
8787
- flexShrink: 0,
8788
- alignItems: "center",
8789
- justifyContent: "center",
8790
- borderRadius: "var(--radius-md)"
8791
- },
8792
- children: /* @__PURE__ */ jsx39(X4, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" })
8793
- }
8794
- );
8795
- }
8796
8721
  var CLEAR_CLEARANCE = 32;
8797
- var INLINE_HEIGHT = 40;
8798
- var HIT_AREA = 44;
8799
- var HIT_INSET = 8;
8722
+ var IDLE_HEIGHT = 40;
8800
8723
  var FLOATING_BOTTOM = "calc(var(--space-4) + env(safe-area-inset-bottom))";
8801
8724
  var floatingStyle = {
8802
8725
  position: "sticky",
@@ -8813,28 +8736,10 @@ var floatingStyle = {
8813
8736
  padding: "var(--space-2) var(--space-4) var(--space-3)",
8814
8737
  boxShadow: "var(--shadow-8)"
8815
8738
  };
8816
- var inlineStyle = {
8817
- position: "sticky",
8818
- top: 0,
8819
- zIndex: "var(--z-sticky)",
8820
- display: "flex",
8821
- boxSizing: "border-box",
8822
- height: INLINE_HEIGHT,
8823
- alignItems: "center",
8824
- gap: "var(--space-2)",
8825
- borderRadius: "var(--radius-md)",
8826
- border: "1px solid var(--border)",
8827
- background: "var(--bg-surface)",
8828
- padding: "0 var(--space-1) 0 var(--space-3)",
8829
- boxShadow: "var(--shadow-2)",
8830
- fontFamily: "var(--font-sans)",
8831
- fontSize: 13,
8832
- fontVariantNumeric: "tabular-nums"
8833
- };
8834
8739
  var idleLineStyle = {
8835
8740
  display: "flex",
8836
8741
  boxSizing: "border-box",
8837
- height: INLINE_HEIGHT,
8742
+ height: IDLE_HEIGHT,
8838
8743
  overflow: "hidden",
8839
8744
  alignItems: "center",
8840
8745
  columnGap: "var(--space-3)",
@@ -8844,22 +8749,6 @@ var idleLineStyle = {
8844
8749
  fontVariantNumeric: "tabular-nums",
8845
8750
  color: "var(--text-secondary)"
8846
8751
  };
8847
- var warnedInline = false;
8848
- function warnInlineOnce() {
8849
- if (warnedInline || typeof process === "undefined" || process.env.NODE_ENV === "production") {
8850
- return;
8851
- }
8852
- warnedInline = true;
8853
- console.warn('BulkActionBar: placement="inline" is deprecated and removed in the next minor. Use "floating".');
8854
- }
8855
- var warnedTrailing = false;
8856
- function warnTrailingOnce() {
8857
- if (warnedTrailing || typeof process === "undefined" || process.env.NODE_ENV === "production") {
8858
- return;
8859
- }
8860
- warnedTrailing = true;
8861
- console.warn("BulkActionBar: the floating card ignores `trailing`. Put edit-mode controls at the right end of the toolbar.");
8862
- }
8863
8752
  var OFFSET_PROPERTY = "--olun-bulk-bar-offset";
8864
8753
  var LIFT_ZONE = 204;
8865
8754
  var cardOffsets = /* @__PURE__ */ new Map();
@@ -8963,104 +8852,31 @@ function useBottomOffset(card) {
8963
8852
  if (card && typeof ResizeObserver === "undefined") reportOffset(key, card);
8964
8853
  });
8965
8854
  }
8966
- function useCompactSummary(slot, enabled) {
8967
- const [fullWidth, setFullWidth] = React36.useState(null);
8968
- const measure = React36.useCallback(() => {
8969
- if (!slot) return;
8970
- setFullWidth((prev) => {
8971
- if (prev === null) return slot.scrollWidth > slot.clientWidth ? slot.scrollWidth : null;
8972
- return slot.clientWidth >= prev ? null : prev;
8973
- });
8974
- }, [slot]);
8975
- useIsomorphicLayoutEffect2(() => {
8976
- if (enabled) measure();
8977
- });
8978
- React36.useEffect(() => {
8979
- if (!enabled || !slot || typeof ResizeObserver === "undefined") return;
8980
- const observer = new ResizeObserver(measure);
8981
- observer.observe(slot);
8982
- return () => observer.disconnect();
8983
- }, [enabled, slot, measure]);
8984
- return enabled && fullWidth !== null;
8985
- }
8986
8855
  function BulkActionBar({
8987
8856
  count,
8988
8857
  actions,
8989
8858
  onClear,
8990
8859
  emptyHint,
8991
- placement = "floating",
8860
+ // Removed props are dropped here so a spread or untyped caller never leaks them to the DOM.
8861
+ placement: _placement,
8862
+ compactSummary: _compactSummary,
8863
+ trailing: _trailing,
8992
8864
  unit = "\uAC1C",
8993
8865
  summary,
8994
- compactSummary,
8995
8866
  idleContent,
8996
- trailing,
8997
8867
  className,
8998
8868
  style,
8999
8869
  ...props
9000
8870
  }) {
9001
- const inline = placement === "inline";
9002
- if (inline) warnInlineOnce();
9003
- const hasTrailing = trailing !== void 0 && trailing !== null;
9004
- if (!inline && hasTrailing) warnTrailingOnce();
9005
- const trailingSlot = inline && hasTrailing ? /* @__PURE__ */ jsx39(
9006
- "div",
9007
- {
9008
- "data-slot": "bulk-action-bar-trailing",
9009
- style: {
9010
- display: "flex",
9011
- flexShrink: 0,
9012
- alignItems: "center",
9013
- gap: "var(--space-2)"
9014
- },
9015
- children: trailing
9016
- }
9017
- ) : null;
9018
- const [summaryElement, setSummaryElement] = React36.useState(null);
9019
- const compact = useCompactSummary(
9020
- summaryElement,
9021
- inline && compactSummary !== void 0 && compactSummary !== null
9022
- );
9023
8871
  const [card, setCard] = React36.useState(null);
9024
8872
  useBottomOffset(card);
9025
- if (count === 0 && idleContent !== void 0 && trailingSlot) {
9026
- return /* @__PURE__ */ jsxs35(
9027
- "div",
9028
- {
9029
- "data-slot": "bulk-action-bar",
9030
- "data-placement": placement,
9031
- "data-state": "idle",
9032
- className,
9033
- style: { ...idleLineStyle, overflow: "visible", ...style },
9034
- ...props,
9035
- children: [
9036
- /* @__PURE__ */ jsx39(
9037
- "div",
9038
- {
9039
- role: "status",
9040
- "data-slot": "bulk-action-bar-idle",
9041
- style: {
9042
- display: "flex",
9043
- flex: "1 1 auto",
9044
- minWidth: 0,
9045
- alignItems: "center",
9046
- columnGap: "var(--space-3)",
9047
- overflow: "hidden"
9048
- },
9049
- children: idleContent
9050
- }
9051
- ),
9052
- trailingSlot
9053
- ]
9054
- }
9055
- );
9056
- }
9057
8873
  if (count === 0 && idleContent !== void 0) {
9058
8874
  return /* @__PURE__ */ jsx39(
9059
8875
  "div",
9060
8876
  {
9061
8877
  role: "status",
9062
8878
  "data-slot": "bulk-action-bar",
9063
- "data-placement": placement,
8879
+ "data-placement": "floating",
9064
8880
  "data-state": "idle",
9065
8881
  className,
9066
8882
  style: { ...idleLineStyle, ...style },
@@ -9076,38 +8892,25 @@ function BulkActionBar({
9076
8892
  "span",
9077
8893
  {
9078
8894
  "data-slot": "bulk-action-bar-count",
9079
- style: inline ? {
9080
- paddingRight: "var(--space-1)",
8895
+ style: {
8896
+ display: "flex",
8897
+ minHeight: 32,
8898
+ alignItems: "center",
8899
+ paddingRight: CLEAR_CLEARANCE,
9081
8900
  fontFamily: "var(--font-sans)",
9082
8901
  fontSize: 13,
9083
- fontWeight: 600,
8902
+ fontWeight: 500,
9084
8903
  fontVariantNumeric: "tabular-nums",
9085
8904
  color: "var(--text-primary)",
9086
- whiteSpace: "nowrap"
9087
- } : (
9088
- // First row, 32px like the ✕ beside it; the right padding keeps text clear of it,
9089
- // and a long unbroken unit or hint breaks instead of running under it.
9090
- {
9091
- display: "flex",
9092
- minHeight: 32,
9093
- alignItems: "center",
9094
- paddingRight: CLEAR_CLEARANCE,
9095
- fontFamily: "var(--font-sans)",
9096
- fontSize: 13,
9097
- fontWeight: 500,
9098
- fontVariantNumeric: "tabular-nums",
9099
- color: "var(--text-primary)",
9100
- wordBreak: "keep-all",
9101
- overflowWrap: "anywhere"
9102
- }
9103
- ),
8905
+ wordBreak: "keep-all",
8906
+ overflowWrap: "anywhere"
8907
+ },
9104
8908
  children: count > 0 ? `${count.toLocaleString("ko-KR")}${unit} \uC120\uD0DD\uB428` : emptyHint
9105
8909
  }
9106
8910
  );
9107
8911
  const summarySlot = summary !== void 0 && summary !== null ? /* @__PURE__ */ jsx39(
9108
8912
  "span",
9109
8913
  {
9110
- ref: setSummaryElement,
9111
8914
  "data-slot": "bulk-action-bar-summary",
9112
8915
  style: {
9113
8916
  display: "flex",
@@ -9117,98 +8920,15 @@ function BulkActionBar({
9117
8920
  fontFamily: "var(--font-sans)",
9118
8921
  fontSize: 13,
9119
8922
  color: "var(--text-secondary)",
9120
- ...inline ? (
9121
- // inline-size containment: the summary never widens the band's parent. The
9122
- // slot clips text, so it is as tall as an IconButton's hit area (overhanging
9123
- // the 40px band) and has that inset as its left gutter: a compact IconButton
9124
- // keeps its full 44px target. The right gutter stays 3px (focus ring) so
9125
- // clipped text keeps clear of the controls.
9126
- {
9127
- flex: "1 1 0",
9128
- alignSelf: "center",
9129
- height: HIT_AREA,
9130
- margin: `0 -3px 0 -${HIT_INSET}px`,
9131
- padding: `0 3px 0 ${HIT_INSET}px`,
9132
- overflow: "hidden",
9133
- whiteSpace: "nowrap",
9134
- contain: "inline-size"
9135
- }
9136
- ) : (
9137
- // Its own row at the card's full inner width; wraps, never clips.
9138
- { flexWrap: "wrap", lineHeight: 1.5, wordBreak: "keep-all", overflowWrap: "anywhere" }
9139
- )
8923
+ // Its own row at the card's full inner width; wraps, never clips.
8924
+ flexWrap: "wrap",
8925
+ lineHeight: 1.5,
8926
+ wordBreak: "keep-all",
8927
+ overflowWrap: "anywhere"
9140
8928
  },
9141
- children: compact ? compactSummary : summary
8929
+ children: summary
9142
8930
  }
9143
8931
  ) : null;
9144
- if (inline) {
9145
- const actionGroup = /* @__PURE__ */ jsx39(
9146
- "div",
9147
- {
9148
- "data-slot": "bulk-action-bar-actions",
9149
- style: {
9150
- display: "flex",
9151
- minWidth: 0,
9152
- flexWrap: "nowrap",
9153
- alignItems: "center",
9154
- justifyContent: "flex-end",
9155
- gap: 2
9156
- },
9157
- children: actions.map((action) => /* @__PURE__ */ jsx39(ActionButton, { action }, action.key))
9158
- }
9159
- );
9160
- return /* @__PURE__ */ jsxs35(
9161
- "div",
9162
- {
9163
- role: "toolbar",
9164
- "aria-label": "\uC120\uD0DD \uD56D\uBAA9 \uC77C\uAD04 \uC791\uC5C5",
9165
- "data-slot": "bulk-action-bar",
9166
- "data-placement": "inline",
9167
- className,
9168
- style: { ...inlineStyle, ...style },
9169
- ...props,
9170
- children: [
9171
- /* @__PURE__ */ jsxs35(
9172
- "div",
9173
- {
9174
- role: "status",
9175
- "data-slot": "bulk-action-bar-state",
9176
- style: {
9177
- display: "flex",
9178
- flex: "1 1 auto",
9179
- minWidth: 0,
9180
- alignItems: "center",
9181
- columnGap: "var(--space-3)"
9182
- },
9183
- children: [
9184
- countLabel,
9185
- summarySlot
9186
- ]
9187
- }
9188
- ),
9189
- /* @__PURE__ */ jsxs35(
9190
- "div",
9191
- {
9192
- "data-slot": "bulk-action-bar-controls",
9193
- style: {
9194
- display: "flex",
9195
- marginLeft: "auto",
9196
- alignItems: "center",
9197
- gap: "var(--space-1)"
9198
- },
9199
- children: [
9200
- count > 0 && actions.length > 0 ? /* @__PURE__ */ jsx39(Divider, {}) : null,
9201
- actionGroup,
9202
- /* @__PURE__ */ jsx39(Divider, {}),
9203
- /* @__PURE__ */ jsx39(ClearButton, { onClear })
9204
- ]
9205
- }
9206
- ),
9207
- trailingSlot
9208
- ]
9209
- }
9210
- );
9211
- }
9212
8932
  return /* @__PURE__ */ jsxs35(
9213
8933
  "div",
9214
8934
  {
@@ -10607,14 +10327,15 @@ var modeToggleVariants = cva19(
10607
10327
  var modeToggleItemVariants = cva19(
10608
10328
  [
10609
10329
  "inline-flex min-h-[28px] cursor-pointer items-center justify-center gap-[var(--space-1)]",
10610
- "rounded-[calc(var(--radius-md)_-_2px)] px-[var(--space-3)] py-[var(--space-1)]",
10330
+ "rounded-[calc(var(--radius-md)_-_2px)] border border-transparent px-[var(--space-3)] py-[var(--space-1)]",
10611
10331
  "font-[family-name:var(--font-display)] text-xs font-medium leading-none",
10612
- "text-text-secondary transition-[background-color,color,box-shadow]",
10332
+ "text-text-secondary transition-[background-color,border-color,color,box-shadow]",
10613
10333
  "duration-[var(--dur-fast)] ease-[var(--ease-standard)]",
10614
10334
  "hover:text-foreground",
10615
10335
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]",
10616
10336
  "disabled:cursor-not-allowed disabled:text-text-disabled disabled:hover:text-text-disabled",
10617
- "data-[state=active]:bg-[var(--bg-surface)] data-[state=active]:font-semibold",
10337
+ "data-[state=active]:border-[var(--text-tertiary)] data-[state=active]:bg-[var(--fill-on-inset)]",
10338
+ "data-[state=active]:font-semibold",
10618
10339
  "data-[state=active]:text-foreground data-[state=active]:shadow-[var(--shadow-1)]",
10619
10340
  "[&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0 [&_svg]:stroke-[1.75]"
10620
10341
  ].join(" ")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@olundot/ui",
3
- "version": "0.20.2",
3
+ "version": "0.21.1",
4
4
  "description": "OLUN. shared React UI components built on OLUN design tokens",
5
5
  "license": "MIT",
6
6
  "keywords": [