plainframe-ui 0.1.5 → 0.1.7

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
@@ -5958,9 +5958,8 @@ var Button = React20.memo(React20.forwardRef(({
5958
5958
  }, ref) => {
5959
5959
  const theme = usePlainframeUITheme();
5960
5960
  const focusRing = useFocusRing();
5961
- const normalizedVariant = variant === "ghost-destructive" ? "ghost-destructive" : variant;
5962
5961
  const S = useMemo10(() => getSize3(theme, size), [theme, size]);
5963
- const vis = useMemo10(() => resolveVisuals(theme, normalizedVariant), [theme, normalizedVariant]);
5962
+ const vis = useMemo10(() => resolveVisuals(theme, variant), [theme, variant]);
5964
5963
  const isIconOnly = useMemo10(
5965
5964
  () => !startIcon && !endIcon && !hasText(children) && React20.Children.count(children) === 1,
5966
5965
  [startIcon, endIcon, children]
@@ -6144,7 +6143,7 @@ var Button = React20.memo(React20.forwardRef(({
6144
6143
  {
6145
6144
  ref,
6146
6145
  type: "type" in props && props.type ? props.type : "button",
6147
- "data-variant": normalizedVariant,
6146
+ "data-variant": variant,
6148
6147
  className: ["plainframe-ui-button", className || ""].join(" ").trim(),
6149
6148
  css: [
6150
6149
  rootBase,
@@ -9777,12 +9776,10 @@ var RadioItem = ({
9777
9776
  fontSize: theme.fontSizes.md,
9778
9777
  fontWeight: 500,
9779
9778
  padding: theme.spacing.sm,
9780
- // Hover applies to the CIRCLE only if NOT checked
9781
9779
  "&:hover .plainframe-ui-radio-circle-outer": isDisabled || isChecked ? {} : {
9782
9780
  background: hoverCircleBg,
9783
9781
  boxShadow: variant === "outlined" ? `inset 0 0 0 ${theme.componentHeights.border} ${stroke}` : "none"
9784
9782
  },
9785
- // Focus ring hint on circle
9786
9783
  "&:focus-visible .plainframe-ui-radio-circle-outer": {
9787
9784
  outline: "none",
9788
9785
  filter: "brightness(1.06)"
@@ -10010,7 +10007,6 @@ function Select({
10010
10007
  value,
10011
10008
  defaultValue,
10012
10009
  onChange,
10013
- // not wired here; your Menu components should manage selection & call you
10014
10010
  label,
10015
10011
  placeholder = "Select\u2026",
10016
10012
  startIcon,
@@ -10982,13 +10978,250 @@ var Stepper = ({
10982
10978
  );
10983
10979
  };
10984
10980
 
10981
+ // src/components/Swap.tsx
10982
+ import React44, {
10983
+ useState as useState20,
10984
+ useCallback as useCallback13,
10985
+ useEffect as useEffect14,
10986
+ useRef as useRef14,
10987
+ Children as Children6,
10988
+ isValidElement as isValidElement15,
10989
+ createContext as createContext6,
10990
+ useContext as useContext9
10991
+ } from "react";
10992
+ import { css as css42, keyframes as keyframes3 } from "@emotion/react";
10993
+ import { jsx as jsx50 } from "@emotion/react/jsx-runtime";
10994
+ var SwapContext = createContext6(null);
10995
+ var useSwapContext = () => {
10996
+ const ctx = useContext9(SwapContext);
10997
+ if (!ctx) {
10998
+ throw new Error("SwapItem must be used within Swap");
10999
+ }
11000
+ return ctx;
11001
+ };
11002
+ var ANIMATION_MS = 220;
11003
+ var scaleAnim = keyframes3`
11004
+ 0% { transform: scale(1); }
11005
+ 45% { transform: scale(0.85); }
11006
+ 55% { transform: scale(0.85); }
11007
+ 100% { transform: scale(1); }
11008
+ `;
11009
+ var rotateAnim = keyframes3`
11010
+ 0% { transform: rotate(0deg); }
11011
+ 49% { transform: rotate(179deg); }
11012
+ 51% { transform: rotate(181deg); }
11013
+ 100% { transform: rotate(360deg); }
11014
+ `;
11015
+ var scaleRotateAnim = keyframes3`
11016
+ 0% { transform: scale(1) rotate(0deg); }
11017
+ 40% { transform: scale(0.9) rotate(140deg); }
11018
+ 50% { transform: scale(0.85) rotate(180deg); }
11019
+ 60% { transform: scale(0.9) rotate(220deg); }
11020
+ 100% { transform: scale(1) rotate(360deg); }
11021
+ `;
11022
+ var SwapItem = React44.forwardRef(
11023
+ ({ value, children, className = "", css: customCss }, ref) => {
11024
+ const {
11025
+ activeValue,
11026
+ animationEffect,
11027
+ isAnimating,
11028
+ transitionFrom,
11029
+ transitionTo,
11030
+ transitionPhase
11031
+ } = useSwapContext();
11032
+ const isOverlayEffect = animationEffect === "rotate" || animationEffect === "scale-rotate" || animationEffect === "scale";
11033
+ let shouldShow = false;
11034
+ let opacity = 0;
11035
+ if (!isAnimating || !isOverlayEffect) {
11036
+ shouldShow = value === activeValue;
11037
+ opacity = shouldShow ? 1 : 0;
11038
+ } else {
11039
+ const isFrom = value === transitionFrom;
11040
+ const isTo = value === transitionTo;
11041
+ if (isFrom || isTo) {
11042
+ shouldShow = true;
11043
+ if (transitionPhase === "first") {
11044
+ opacity = isFrom ? 1 : 0;
11045
+ } else {
11046
+ opacity = isTo ? 1 : 0;
11047
+ }
11048
+ } else {
11049
+ shouldShow = false;
11050
+ opacity = 0;
11051
+ }
11052
+ }
11053
+ const itemCss = css42({
11054
+ gridArea: "1 / 1 / 2 / 2",
11055
+ transition: `opacity ${ANIMATION_MS / 2}ms ease-out`,
11056
+ opacity,
11057
+ display: shouldShow ? "block" : "none"
11058
+ });
11059
+ return /* @__PURE__ */ jsx50(
11060
+ "div",
11061
+ {
11062
+ ref,
11063
+ className: `pfui-swap-item ${className}`,
11064
+ css: [itemCss, customCss],
11065
+ "aria-hidden": opacity === 0,
11066
+ children
11067
+ }
11068
+ );
11069
+ }
11070
+ );
11071
+ SwapItem.displayName = "SwapItem";
11072
+ var Swap = React44.forwardRef(
11073
+ ({
11074
+ variant = "toggle",
11075
+ animationEffect = "scale",
11076
+ flashDuration = 750,
11077
+ value: controlledValue,
11078
+ defaultValue,
11079
+ onChange,
11080
+ disabled = false,
11081
+ children,
11082
+ className = "",
11083
+ css: customCss
11084
+ }, ref) => {
11085
+ const childArray = Children6.toArray(children).filter(isValidElement15);
11086
+ const values = childArray.filter((child) => child.type === SwapItem).map((child) => child.props.value);
11087
+ const initial = defaultValue ?? values[0] ?? "";
11088
+ const [internalValue, setInternalValue] = useState20(initial);
11089
+ const [isAnimating, setIsAnimating] = useState20(false);
11090
+ const [isFlashing, setIsFlashing] = useState20(false);
11091
+ const [transitionFrom, setTransitionFrom] = useState20(null);
11092
+ const [transitionTo, setTransitionTo] = useState20(null);
11093
+ const [transitionPhase, setTransitionPhase] = useState20("idle");
11094
+ const isControlled = controlledValue !== void 0;
11095
+ const activeValue = isControlled ? controlledValue : internalValue;
11096
+ const flashMs = flashDuration ?? 200;
11097
+ const timeoutsRef = useRef14([]);
11098
+ const clearAllTimeouts = () => {
11099
+ timeoutsRef.current.forEach((id) => window.clearTimeout(id));
11100
+ timeoutsRef.current = [];
11101
+ };
11102
+ useEffect14(() => {
11103
+ return () => {
11104
+ clearAllTimeouts();
11105
+ };
11106
+ }, []);
11107
+ const commitValue = (next) => {
11108
+ if (isControlled) {
11109
+ onChange?.(next);
11110
+ } else {
11111
+ setInternalValue(next);
11112
+ }
11113
+ };
11114
+ const runSwap = useCallback13(
11115
+ (from, to, after) => {
11116
+ clearAllTimeouts();
11117
+ setIsAnimating(true);
11118
+ setTransitionFrom(from);
11119
+ setTransitionTo(to);
11120
+ setTransitionPhase("first");
11121
+ const mid = window.setTimeout(() => {
11122
+ commitValue(to);
11123
+ setTransitionPhase("second");
11124
+ }, ANIMATION_MS / 2);
11125
+ const end = window.setTimeout(() => {
11126
+ setIsAnimating(false);
11127
+ setTransitionFrom(null);
11128
+ setTransitionTo(null);
11129
+ setTransitionPhase("idle");
11130
+ after?.();
11131
+ }, ANIMATION_MS);
11132
+ timeoutsRef.current.push(mid, end);
11133
+ },
11134
+ [isControlled, onChange]
11135
+ );
11136
+ const handleSwap = useCallback13(() => {
11137
+ if (disabled || isAnimating || isFlashing || values.length <= 1) return;
11138
+ const base = initial;
11139
+ const baseIndex = values.indexOf(base);
11140
+ const nextIndexFromBase = baseIndex === -1 ? 0 : (baseIndex + 1) % values.length;
11141
+ const nextFromBase = values[nextIndexFromBase];
11142
+ if (variant === "toggle") {
11143
+ const currentIndex = values.indexOf(activeValue);
11144
+ const nextIndex = (currentIndex + 1) % values.length;
11145
+ const nextValue = values[nextIndex];
11146
+ runSwap(activeValue, nextValue);
11147
+ } else {
11148
+ setIsFlashing(true);
11149
+ const flashValue = nextFromBase === base ? values[(nextIndexFromBase + 1) % values.length] : nextFromBase;
11150
+ runSwap(base, flashValue, () => {
11151
+ const pause = window.setTimeout(() => {
11152
+ runSwap(flashValue, base, () => {
11153
+ setIsFlashing(false);
11154
+ });
11155
+ }, flashMs);
11156
+ timeoutsRef.current.push(pause);
11157
+ });
11158
+ }
11159
+ }, [
11160
+ disabled,
11161
+ isAnimating,
11162
+ isFlashing,
11163
+ values,
11164
+ activeValue,
11165
+ variant,
11166
+ flashMs,
11167
+ runSwap,
11168
+ initial
11169
+ ]);
11170
+ const animationKeyframes = animationEffect === "rotate" ? rotateAnim : animationEffect === "scale-rotate" ? scaleRotateAnim : scaleAnim;
11171
+ const swapCss = css42({
11172
+ position: "relative",
11173
+ display: "inline-grid",
11174
+ cursor: disabled ? "not-allowed" : "pointer",
11175
+ opacity: disabled ? 0.55 : 1,
11176
+ transformOrigin: "center",
11177
+ backfaceVisibility: "hidden",
11178
+ ...isAnimating && {
11179
+ animation: `${animationKeyframes} ${ANIMATION_MS}ms cubic-bezier(0.4, 0, 0.2, 1)`
11180
+ }
11181
+ });
11182
+ const contextValue = {
11183
+ activeValue,
11184
+ variant,
11185
+ animationEffect,
11186
+ flashDuration: flashMs,
11187
+ isAnimating,
11188
+ handleSwap,
11189
+ disabled,
11190
+ transitionFrom,
11191
+ transitionTo,
11192
+ transitionPhase
11193
+ };
11194
+ return /* @__PURE__ */ jsx50(SwapContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx50(
11195
+ "div",
11196
+ {
11197
+ ref,
11198
+ className: `pfui-swap ${className}`,
11199
+ css: [swapCss, customCss],
11200
+ onClick: handleSwap,
11201
+ role: "button",
11202
+ tabIndex: disabled ? -1 : 0,
11203
+ onKeyDown: (e) => {
11204
+ if (disabled) return;
11205
+ if (e.key === "Enter" || e.key === " ") {
11206
+ e.preventDefault();
11207
+ handleSwap();
11208
+ }
11209
+ },
11210
+ "aria-disabled": disabled,
11211
+ children
11212
+ }
11213
+ ) });
11214
+ }
11215
+ );
11216
+ Swap.displayName = "Swap";
11217
+
10985
11218
  // src/components/Tabs.tsx
10986
- import React44 from "react";
10987
- import { css as css42 } from "@emotion/react";
10988
- import { Fragment as Fragment8, jsx as jsx50, jsxs as jsxs29 } from "@emotion/react/jsx-runtime";
11219
+ import React45 from "react";
11220
+ import { css as css43 } from "@emotion/react";
11221
+ import { Fragment as Fragment8, jsx as jsx51, jsxs as jsxs29 } from "@emotion/react/jsx-runtime";
10989
11222
  var Tab = () => null;
10990
11223
  Tab.displayName = "PF.Tab";
10991
- var TabContent = ({ children }) => /* @__PURE__ */ jsx50(Fragment8, { children });
11224
+ var TabContent = ({ children }) => /* @__PURE__ */ jsx51(Fragment8, { children });
10992
11225
  TabContent.displayName = "PF.TabContent";
10993
11226
  function unwrapEmotion2(child) {
10994
11227
  const propsAny = child.props;
@@ -11021,11 +11254,11 @@ var Tabs = ({
11021
11254
  const stretch = fullWidth || width != null;
11022
11255
  const effAlign = align ?? (isV ? "left" : "center");
11023
11256
  const justifyMap = { left: "flex-start", center: "center", right: "flex-end" };
11024
- const { tabs, contents } = React44.useMemo(() => {
11257
+ const { tabs, contents } = React45.useMemo(() => {
11025
11258
  const t = [];
11026
11259
  const c = [];
11027
- React44.Children.forEach(children, (child) => {
11028
- if (!React44.isValidElement(child)) return;
11260
+ React45.Children.forEach(children, (child) => {
11261
+ if (!React45.isValidElement(child)) return;
11029
11262
  const { type: origType, props } = unwrapEmotion2(child);
11030
11263
  const isTab = origType === Tab || origType?.displayName === Tab.displayName;
11031
11264
  const isContent = origType === TabContent || origType?.displayName === TabContent.displayName;
@@ -11041,20 +11274,20 @@ var Tabs = ({
11041
11274
  });
11042
11275
  return { tabs: t, contents: c };
11043
11276
  }, [children]);
11044
- const firstEnabled = React44.useMemo(() => tabs.find((t) => !t.disabled)?.value, [tabs]);
11045
- const [internal, setInternal] = React44.useState(() => {
11277
+ const firstEnabled = React45.useMemo(() => tabs.find((t) => !t.disabled)?.value, [tabs]);
11278
+ const [internal, setInternal] = React45.useState(() => {
11046
11279
  const ok = defaultValue !== void 0 && tabs.some((t) => t.value === defaultValue && !t.disabled);
11047
11280
  return ok ? defaultValue : firstEnabled;
11048
11281
  });
11049
11282
  const isControlled = value !== void 0;
11050
11283
  const currentValue = isControlled ? value : internal;
11051
- const listRef = React44.useRef(null);
11052
- const btnRefs = React44.useRef([]);
11284
+ const listRef = React45.useRef(null);
11285
+ const btnRefs = React45.useRef([]);
11053
11286
  const activeIndex = Math.max(0, tabs.findIndex((t) => t.value === currentValue));
11054
- const [indicator, setIndicator] = React44.useState({ left: 0, top: 0, width: 0, height: 0 });
11055
- const [ready, setReady] = React44.useState(false);
11056
- const [animate, setAnimate] = React44.useState(false);
11057
- const measure = React44.useCallback(() => {
11287
+ const [indicator, setIndicator] = React45.useState({ left: 0, top: 0, width: 0, height: 0 });
11288
+ const [ready, setReady] = React45.useState(false);
11289
+ const [animate, setAnimate] = React45.useState(false);
11290
+ const measure = React45.useCallback(() => {
11058
11291
  const list = listRef.current;
11059
11292
  const btn = btnRefs.current[activeIndex];
11060
11293
  if (!list || !btn) return;
@@ -11062,14 +11295,14 @@ var Tabs = ({
11062
11295
  const r = btn.getBoundingClientRect();
11063
11296
  setIndicator({ left: r.left - listRect.left, top: r.top - listRect.top, width: r.width, height: r.height });
11064
11297
  }, [activeIndex]);
11065
- React44.useLayoutEffect(() => {
11298
+ React45.useLayoutEffect(() => {
11066
11299
  measure();
11067
11300
  if (!ready) {
11068
11301
  setReady(true);
11069
11302
  requestAnimationFrame(() => setAnimate(true));
11070
11303
  }
11071
11304
  }, [measure, ready]);
11072
- React44.useEffect(() => {
11305
+ React45.useEffect(() => {
11073
11306
  const ro = new ResizeObserver(() => measure());
11074
11307
  if (listRef.current) ro.observe(listRef.current);
11075
11308
  const btn = btnRefs.current[activeIndex];
@@ -11116,14 +11349,14 @@ var Tabs = ({
11116
11349
  const thumbBg = variant === "subtle" ? theme.surface.panelBg ?? theme.surface.panelBg : variant === "ghost" ? theme.surface.subtleBg : "transparent";
11117
11350
  const underlineColor = theme.text.primary;
11118
11351
  const showThumb = variant === "subtle" || variant === "ghost" || variant === "underlined";
11119
- const rootCss2 = css42({
11352
+ const rootCss2 = css43({
11120
11353
  "--pf-ease": "cubic-bezier(.4,0,.2,1)",
11121
11354
  display: "flex",
11122
11355
  flexDirection: "column",
11123
11356
  width: fullWidth ? "100%" : width == null ? "auto" : typeof width === "number" ? `${width}px` : width
11124
11357
  });
11125
11358
  const needsPad = variant === "subtle";
11126
- const trackBaseCss = css42({
11359
+ const trackBaseCss = css43({
11127
11360
  position: "relative",
11128
11361
  display: stretch ? "flex" : "inline-flex",
11129
11362
  width: stretch ? "100%" : "auto",
@@ -11135,7 +11368,7 @@ var Tabs = ({
11135
11368
  background: trackBg,
11136
11369
  borderRadius: variant === "subtle" ? rounded ? isV ? theme.radius.lg : theme.radius.full : theme.radius.lg : "none"
11137
11370
  });
11138
- const thumbBaseCss = css42({
11371
+ const thumbBaseCss = css43({
11139
11372
  position: "absolute",
11140
11373
  zIndex: 0,
11141
11374
  pointerEvents: "none",
@@ -11147,10 +11380,10 @@ var Tabs = ({
11147
11380
  ...isV ? { top: `${indicator.top}px`, height: `${indicator.height}px`, left: theme.spacing.xs, right: theme.spacing.xs } : { left: `${indicator.left}px`, width: `${indicator.width}px`, top: theme.spacing.xs, bottom: theme.spacing.xs },
11148
11381
  boxShadow: shadow && variant === "subtle" ? "0 1px 3px rgba(0,0,0,0.04), 0 6px 16px rgba(0,0,0,0.04)" : "none"
11149
11382
  });
11150
- const underlineCss = css42(
11383
+ const underlineCss = css43(
11151
11384
  variant !== "underlined" ? {} : isV ? { background: "transparent", top: `${indicator.top}px`, height: `${indicator.height}px`, left: 0, width: 0, borderLeft: `2px solid ${underlineColor}`, borderBottom: "none", borderRadius: 2 } : { background: "transparent", left: `${indicator.left}px`, width: `${indicator.width}px`, bottom: 0, top: "auto", height: 0, borderBottom: `2px solid ${underlineColor}`, borderLeft: "none", borderRadius: 2 }
11152
11385
  );
11153
- const baseTabCss = css42({
11386
+ const baseTabCss = css43({
11154
11387
  position: "relative",
11155
11388
  zIndex: 1,
11156
11389
  border: "none",
@@ -11174,7 +11407,7 @@ var Tabs = ({
11174
11407
  "&:hover": { color: textPrimary },
11175
11408
  "&[aria-disabled='true'], &:disabled": { opacity: 0.55, cursor: "not-allowed", color: disabledText }
11176
11409
  });
11177
- const contentWrapCss = css42({
11410
+ const contentWrapCss = css43({
11178
11411
  display: "inline-flex",
11179
11412
  alignItems: "center",
11180
11413
  justifyContent: isV ? justifyMap[effAlign] : "center",
@@ -11182,8 +11415,8 @@ var Tabs = ({
11182
11415
  width: "100%",
11183
11416
  flexDirection: titlePosition === "top" ? "column-reverse" : titlePosition === "bottom" ? "column" : titlePosition === "left" ? "row-reverse" : "row"
11184
11417
  });
11185
- const panelCss = css42({ marginTop: theme.spacing.sm, width: "100%" });
11186
- const idBase = React44.useId();
11418
+ const panelCss = css43({ marginTop: theme.spacing.sm, width: "100%" });
11419
+ const idBase = React45.useId();
11187
11420
  const panelIdByValue = /* @__PURE__ */ new Map();
11188
11421
  contents.forEach((c, i) => panelIdByValue.set(c.value, `${idBase}-panel-${i}`));
11189
11422
  const tabIdForIndex = (i) => `${idBase}-tab-${i}`;
@@ -11198,10 +11431,10 @@ var Tabs = ({
11198
11431
  onKeyDown,
11199
11432
  css: [trackBaseCss, userTrackCss],
11200
11433
  children: [
11201
- showThumb && /* @__PURE__ */ jsx50("div", { className: "plainframe-ui-tabs-thumb", css: [thumbBaseCss, underlineCss, userThumbCss, activeIndicatorCss] }),
11434
+ showThumb && /* @__PURE__ */ jsx51("div", { className: "plainframe-ui-tabs-thumb", css: [thumbBaseCss, underlineCss, userThumbCss, activeIndicatorCss] }),
11202
11435
  tabs.map((t, i) => {
11203
11436
  const isActive = currentValue === t.value;
11204
- return /* @__PURE__ */ jsx50(
11437
+ return /* @__PURE__ */ jsx51(
11205
11438
  "button",
11206
11439
  {
11207
11440
  ref: (el) => {
@@ -11219,7 +11452,7 @@ var Tabs = ({
11219
11452
  if (!t.disabled) setSelected(t.value);
11220
11453
  },
11221
11454
  css: [baseTabCss, !t.disabled && focusRing(), t.css, isActive ? t.activeCss ?? activeTabCss : void 0],
11222
- children: /* @__PURE__ */ jsx50("span", { className: "plainframe-ui-tab-content", css: contentWrapCss, children: t.node })
11455
+ children: /* @__PURE__ */ jsx51("span", { className: "plainframe-ui-tab-content", css: contentWrapCss, children: t.node })
11223
11456
  },
11224
11457
  String(t.value ?? i)
11225
11458
  );
@@ -11231,7 +11464,7 @@ var Tabs = ({
11231
11464
  const isActive = c.value === currentValue;
11232
11465
  const labelledByIndex = tabs.findIndex((t) => t.value === c.value);
11233
11466
  const labelledBy = labelledByIndex >= 0 ? tabIdForIndex(labelledByIndex) : void 0;
11234
- return /* @__PURE__ */ jsx50(
11467
+ return /* @__PURE__ */ jsx51(
11235
11468
  "div",
11236
11469
  {
11237
11470
  role: "tabpanel",
@@ -11251,17 +11484,17 @@ var Tabs = ({
11251
11484
  // src/components/TextArea.tsx
11252
11485
  import {
11253
11486
  useLayoutEffect as useLayoutEffect3,
11254
- useRef as useRef14,
11255
- useState as useState20,
11487
+ useRef as useRef15,
11488
+ useState as useState21,
11256
11489
  useId as useId4,
11257
11490
  useMemo as useMemo20,
11258
- useCallback as useCallback13
11491
+ useCallback as useCallback14
11259
11492
  } from "react";
11260
- import { css as css43 } from "@emotion/react";
11261
- import { jsx as jsx51, jsxs as jsxs30 } from "@emotion/react/jsx-runtime";
11493
+ import { css as css44 } from "@emotion/react";
11494
+ import { jsx as jsx52, jsxs as jsxs30 } from "@emotion/react/jsx-runtime";
11262
11495
  var u4 = (v) => v == null ? void 0 : typeof v === "number" ? `${v}px` : v;
11263
11496
  var asArr = (v) => v == null ? [] : Array.isArray(v) ? v : [v];
11264
- var mergeCss2 = (...parts) => css43(parts.filter(Boolean));
11497
+ var mergeCss2 = (...parts) => css44(parts.filter(Boolean));
11265
11498
  var TextArea = ({
11266
11499
  label,
11267
11500
  value,
@@ -11341,9 +11574,9 @@ var TextArea = ({
11341
11574
  const N = theme.neutral;
11342
11575
  const T = theme.text;
11343
11576
  const isControlled = value !== void 0;
11344
- const [internal, setInternal] = useState20(defaultValue);
11577
+ const [internal, setInternal] = useState21(defaultValue);
11345
11578
  const curr = isControlled ? value : internal;
11346
- const setValue = useCallback13(
11579
+ const setValue = useCallback14(
11347
11580
  (next) => {
11348
11581
  if (!isControlled) setInternal(next);
11349
11582
  onChange?.(next);
@@ -11360,7 +11593,7 @@ var TextArea = ({
11360
11593
  [variant, borderW, error, theme.palette.danger, theme.surface.border]
11361
11594
  );
11362
11595
  const rootCss2 = useMemo20(
11363
- () => css43({
11596
+ () => css44({
11364
11597
  boxSizing: "border-box",
11365
11598
  display: "block",
11366
11599
  minWidth: 0,
@@ -11476,7 +11709,7 @@ var TextArea = ({
11476
11709
  ),
11477
11710
  [s.helperFont, maxLength, curr.length, theme.palette.danger, T, userCharCountCss]
11478
11711
  );
11479
- const ref = useRef14(null);
11712
+ const ref = useRef15(null);
11480
11713
  useLayoutEffect3(() => {
11481
11714
  if (typeof window === "undefined") return;
11482
11715
  const el = ref.current;
@@ -11504,8 +11737,8 @@ var TextArea = ({
11504
11737
  const helperId = helperText != null || showCharCount ? `${id ?? reactId}-help` : void 0;
11505
11738
  const inputId = id ?? reactId;
11506
11739
  return /* @__PURE__ */ jsxs30("div", { className: ["plainframe-ui-textarea", className || ""].join(" ").trim(), css: rootCss2, children: [
11507
- label && /* @__PURE__ */ jsx51("label", { htmlFor: inputId, className: "plainframe-ui-textarea-label", css: labelCss2, children: label }),
11508
- /* @__PURE__ */ jsx51(
11740
+ label && /* @__PURE__ */ jsx52("label", { htmlFor: inputId, className: "plainframe-ui-textarea-label", css: labelCss2, children: label }),
11741
+ /* @__PURE__ */ jsx52(
11509
11742
  "div",
11510
11743
  {
11511
11744
  className: "plainframe-ui-textarea-surface",
@@ -11513,7 +11746,7 @@ var TextArea = ({
11513
11746
  "aria-invalid": !!error || void 0,
11514
11747
  "aria-disabled": disabled || void 0,
11515
11748
  onClick: () => !disabled && ref.current?.focus(),
11516
- children: /* @__PURE__ */ jsx51(
11749
+ children: /* @__PURE__ */ jsx52(
11517
11750
  "textarea",
11518
11751
  {
11519
11752
  ref,
@@ -11545,7 +11778,7 @@ var TextArea = ({
11545
11778
  }
11546
11779
  ),
11547
11780
  (helperText != null || showCharCount && maxLength != null) && /* @__PURE__ */ jsxs30("div", { className: "plainframe-ui-textarea-helper-row", css: helperRowCss, children: [
11548
- /* @__PURE__ */ jsx51("span", { id: helperId, className: "plainframe-ui-textarea-helper-text", css: helperTextCss, children: helperText }),
11781
+ /* @__PURE__ */ jsx52("span", { id: helperId, className: "plainframe-ui-textarea-helper-text", css: helperTextCss, children: helperText }),
11549
11782
  showCharCount && maxLength != null && /* @__PURE__ */ jsxs30("span", { className: "plainframe-ui-textarea-char-count", css: charCountCss, children: [
11550
11783
  curr.length,
11551
11784
  "/",
@@ -11556,18 +11789,18 @@ var TextArea = ({
11556
11789
  };
11557
11790
 
11558
11791
  // src/components/Toast.tsx
11559
- import React46, { useEffect as useEffect14, useSyncExternalStore } from "react";
11560
- import { css as css44 } from "@emotion/react";
11792
+ import React47, { useEffect as useEffect15, useSyncExternalStore } from "react";
11793
+ import { css as css45 } from "@emotion/react";
11561
11794
  import { AnimatePresence as AnimatePresence5, motion as motion5, useAnimationControls } from "framer-motion";
11562
11795
  import { X as X4 } from "lucide-react";
11563
11796
  import { createPortal } from "react-dom";
11564
- import { Fragment as Fragment9, jsx as jsx52, jsxs as jsxs31 } from "@emotion/react/jsx-runtime";
11797
+ import { Fragment as Fragment9, jsx as jsx53, jsxs as jsxs31 } from "@emotion/react/jsx-runtime";
11565
11798
  var isIterable = (obj) => obj != null && typeof obj[Symbol.iterator] === "function";
11566
11799
  var isPromise = (obj) => !!obj && (typeof obj === "object" || typeof obj === "function") && typeof obj.then === "function";
11567
11800
  function isOptionsInput(x) {
11568
11801
  if (x == null) return false;
11569
11802
  if (typeof x !== "object") return false;
11570
- if (React46.isValidElement(x)) return false;
11803
+ if (React47.isValidElement(x)) return false;
11571
11804
  if (isPromise(x)) return false;
11572
11805
  if (isIterable(x)) return false;
11573
11806
  const keys = Object.keys(x);
@@ -11750,7 +11983,7 @@ var toast = Object.assign(
11750
11983
  }
11751
11984
  if (o.content == null && (o.title != null || o.description != null)) {
11752
11985
  o.content = /* @__PURE__ */ jsxs31("div", { children: [
11753
- o.title && /* @__PURE__ */ jsx52("strong", { style: { display: "block", marginBottom: 2 }, children: o.title }),
11986
+ o.title && /* @__PURE__ */ jsx53("strong", { style: { display: "block", marginBottom: 2 }, children: o.title }),
11754
11987
  o.description
11755
11988
  ] });
11756
11989
  }
@@ -11914,16 +12147,16 @@ function positionCss(pos) {
11914
12147
  };
11915
12148
  return map[pos];
11916
12149
  }
11917
- var rowCss = css44({ display: "flex", alignItems: "flex-start", gap: 10 });
11918
- var iconWrapCss = css44({
12150
+ var rowCss = css45({ display: "flex", alignItems: "flex-start", gap: 10 });
12151
+ var iconWrapCss = css45({
11919
12152
  flex: "0 0 auto",
11920
12153
  paddingTop: 1,
11921
12154
  lineHeight: 0,
11922
12155
  marginLeft: -3,
11923
12156
  "& svg, & img, & canvas, & video": { display: "block" }
11924
12157
  });
11925
- var textCss = css44({ fontSize: 14, lineHeight: 1.4, fontWeight: 500, flex: 1, minWidth: 0 });
11926
- var actionRowCss = css44({ display: "flex", alignItems: "center", gap: 6, marginRight: -2 });
12158
+ var textCss = css45({ fontSize: 14, lineHeight: 1.4, fontWeight: 500, flex: 1, minWidth: 0 });
12159
+ var actionRowCss = css45({ display: "flex", alignItems: "center", gap: 6, marginRight: -2 });
11927
12160
  function ToastHost() {
11928
12161
  const snap = useSyncExternalStore(store.subscribe.bind(store), () => store.snapshot, () => store.snapshot);
11929
12162
  const theme = usePlainframeUITheme();
@@ -11940,7 +12173,7 @@ function ToastHost() {
11940
12173
  ...positionCss(cfg.position),
11941
12174
  ...cfg.styles.stack ?? {}
11942
12175
  };
11943
- return /* @__PURE__ */ jsx52("div", { className: "plainframe-ui-toast-stack", css: css44(stackStyle), children: /* @__PURE__ */ jsx52(AnimatePresence5, { initial: false, children: list.map((t, index) => {
12176
+ return /* @__PURE__ */ jsx53("div", { className: "plainframe-ui-toast-stack", css: css45(stackStyle), children: /* @__PURE__ */ jsx53(AnimatePresence5, { initial: false, children: list.map((t, index) => {
11944
12177
  const from = snap.enterFrom[t.id] || "tail";
11945
12178
  const enterY = isBottom ? from === "head" ? -16 : 16 : from === "head" ? 16 : -16;
11946
12179
  const mt = index > 0 ? cfg.gutter : 0;
@@ -11978,8 +12211,8 @@ function ToastHost() {
11978
12211
  } else if (dismissMode === "never") {
11979
12212
  modeStyles[closeSel] = { display: "none" };
11980
12213
  }
11981
- const wrapCss = css44({ ...baseSurface, ...extraSurface, ...modeStyles });
11982
- const closeCss = css44({
12214
+ const wrapCss = css45({ ...baseSurface, ...extraSurface, ...modeStyles });
12215
+ const closeCss = css45({
11983
12216
  position: "absolute",
11984
12217
  top: 8,
11985
12218
  right: 8,
@@ -12000,10 +12233,10 @@ function ToastHost() {
12000
12233
  let content;
12001
12234
  if (t.bare && t.render) {
12002
12235
  const inner = typeof t.render === "function" ? t.render(ctx) : t.render;
12003
- content = /* @__PURE__ */ jsx52("div", { style: { pointerEvents: "auto" }, onClick: (e) => t.onClick?.(t.id, e), children: inner });
12236
+ content = /* @__PURE__ */ jsx53("div", { style: { pointerEvents: "auto" }, onClick: (e) => t.onClick?.(t.id, e), children: inner });
12004
12237
  } else if (cfg.bareRenderer && cfg.renderer) {
12005
12238
  const inner = typeof cfg.renderer === "function" ? cfg.renderer(ctx) : cfg.renderer;
12006
- content = /* @__PURE__ */ jsx52("div", { style: { pointerEvents: "auto" }, onClick: (e) => t.onClick?.(t.id, e), children: inner });
12239
+ content = /* @__PURE__ */ jsx53("div", { style: { pointerEvents: "auto" }, onClick: (e) => t.onClick?.(t.id, e), children: inner });
12007
12240
  } else {
12008
12241
  let innerBlock;
12009
12242
  if (cfg.renderer) {
@@ -12013,16 +12246,16 @@ function ToastHost() {
12013
12246
  } else {
12014
12247
  innerBlock = /* @__PURE__ */ jsxs31(Fragment9, { children: [
12015
12248
  /* @__PURE__ */ jsxs31("div", { css: rowCss, children: [
12016
- t.startIcon && /* @__PURE__ */ jsx52("div", { css: iconWrapCss, children: t.startIcon }),
12017
- /* @__PURE__ */ jsx52("div", { css: textCss, children: t.content }),
12018
- t.endIcon && /* @__PURE__ */ jsx52("div", { css: iconWrapCss, children: t.endIcon })
12249
+ t.startIcon && /* @__PURE__ */ jsx53("div", { css: iconWrapCss, children: t.startIcon }),
12250
+ /* @__PURE__ */ jsx53("div", { css: textCss, children: t.content }),
12251
+ t.endIcon && /* @__PURE__ */ jsx53("div", { css: iconWrapCss, children: t.endIcon })
12019
12252
  ] }),
12020
- t.action && /* @__PURE__ */ jsx52("div", { css: actionRowCss, children: t.action })
12253
+ t.action && /* @__PURE__ */ jsx53("div", { css: actionRowCss, children: t.action })
12021
12254
  ] });
12022
12255
  }
12023
12256
  content = /* @__PURE__ */ jsxs31("div", { css: wrapCss, onClick: (e) => t.onClick?.(t.id, e), children: [
12024
12257
  innerBlock,
12025
- /* @__PURE__ */ jsx52(
12258
+ /* @__PURE__ */ jsx53(
12026
12259
  "button",
12027
12260
  {
12028
12261
  className: "plainframe-ui-toast-close",
@@ -12032,12 +12265,12 @@ function ToastHost() {
12032
12265
  e.stopPropagation();
12033
12266
  toast.dismiss(t.id);
12034
12267
  },
12035
- children: /* @__PURE__ */ jsx52(X4, { strokeWidth: 2.5, size: 14 })
12268
+ children: /* @__PURE__ */ jsx53(X4, { strokeWidth: 2.5, size: 14 })
12036
12269
  }
12037
12270
  )
12038
12271
  ] });
12039
12272
  }
12040
- return /* @__PURE__ */ jsx52(
12273
+ return /* @__PURE__ */ jsx53(
12041
12274
  SwipeItem,
12042
12275
  {
12043
12276
  id: t.id,
@@ -12055,7 +12288,7 @@ function ToastHost() {
12055
12288
  function SwipeItem(props) {
12056
12289
  const { id, isBottom, mt, enterY, width, pauseOnHover, children } = props;
12057
12290
  const controls = useAnimationControls();
12058
- useEffect14(() => {
12291
+ useEffect15(() => {
12059
12292
  controls.start({ opacity: 1, y: 0, height: "auto", x: 0, transition: ENTER_SPRING });
12060
12293
  }, [controls]);
12061
12294
  const itemStyle = {
@@ -12066,12 +12299,12 @@ function SwipeItem(props) {
12066
12299
  maxWidth: width != null ? typeof width === "number" ? `${width}px` : width : "none",
12067
12300
  ...cfg.styles.item ?? {}
12068
12301
  };
12069
- return /* @__PURE__ */ jsx52(
12302
+ return /* @__PURE__ */ jsx53(
12070
12303
  motion5.div,
12071
12304
  {
12072
12305
  layout: true,
12073
12306
  className: "plainframe-ui-toast-item",
12074
- css: css44(itemStyle),
12307
+ css: css45(itemStyle),
12075
12308
  initial: { opacity: 0, y: enterY, height: "auto", x: 0 },
12076
12309
  animate: controls,
12077
12310
  exit: {
@@ -12109,19 +12342,19 @@ function SwipeItem(props) {
12109
12342
  }
12110
12343
  function ToastViewport() {
12111
12344
  ensureHost();
12112
- return hostEl ? createPortal(/* @__PURE__ */ jsx52(ToastHost, {}), hostEl) : null;
12345
+ return hostEl ? createPortal(/* @__PURE__ */ jsx53(ToastHost, {}), hostEl) : null;
12113
12346
  }
12114
12347
 
12115
12348
  // src/components/Tooltip.tsx
12116
- import React47, {
12117
- createContext as createContext6,
12118
- useContext as useContext9,
12349
+ import React48, {
12350
+ createContext as createContext7,
12351
+ useContext as useContext10,
12119
12352
  useId as useId5,
12120
12353
  useMemo as useMemo21,
12121
- useRef as useRef15,
12122
- useState as useState21
12354
+ useRef as useRef16,
12355
+ useState as useState22
12123
12356
  } from "react";
12124
- import { css as css45 } from "@emotion/react";
12357
+ import { css as css46 } from "@emotion/react";
12125
12358
  import {
12126
12359
  useFloating as useFloating3,
12127
12360
  offset,
@@ -12138,7 +12371,7 @@ import {
12138
12371
  FloatingPortal as FloatingPortal3
12139
12372
  } from "@floating-ui/react";
12140
12373
  import { AnimatePresence as AnimatePresence6, motion as motion6 } from "framer-motion";
12141
- import { jsx as jsx53, jsxs as jsxs32 } from "@emotion/react/jsx-runtime";
12374
+ import { jsx as jsx54, jsxs as jsxs32 } from "@emotion/react/jsx-runtime";
12142
12375
  var mergeRefs4 = (...refs) => (node) => {
12143
12376
  for (const r of refs) {
12144
12377
  if (!r) continue;
@@ -12149,9 +12382,9 @@ var mergeRefs4 = (...refs) => (node) => {
12149
12382
  }
12150
12383
  }
12151
12384
  };
12152
- var TooltipCtx = createContext6(null);
12385
+ var TooltipCtx = createContext7(null);
12153
12386
  var useTooltipCtx = () => {
12154
- const v = useContext9(TooltipCtx);
12387
+ const v = useContext10(TooltipCtx);
12155
12388
  if (!v) throw new Error("TooltipTrigger/TooltipContent must be inside <Tooltip>.");
12156
12389
  return v;
12157
12390
  };
@@ -12166,13 +12399,13 @@ var Tooltip = ({
12166
12399
  autoWidth = false,
12167
12400
  disableHoverListener = false
12168
12401
  }) => {
12169
- const [uc, setUc] = useState21(!!defaultOpen);
12402
+ const [uc, setUc] = useState22(!!defaultOpen);
12170
12403
  const open = controlled ?? uc;
12171
12404
  const setOpen = (o) => {
12172
12405
  if (controlled === void 0) setUc(o);
12173
12406
  onOpenChange?.(o);
12174
12407
  };
12175
- const arrowRef = useRef15(null);
12408
+ const arrowRef = useRef16(null);
12176
12409
  const floating = useFloating3({
12177
12410
  placement,
12178
12411
  open,
@@ -12230,7 +12463,7 @@ var Tooltip = ({
12230
12463
  getFloatingProps
12231
12464
  ]
12232
12465
  );
12233
- return /* @__PURE__ */ jsx53(TooltipCtx.Provider, { value: ctx, children });
12466
+ return /* @__PURE__ */ jsx54(TooltipCtx.Provider, { value: ctx, children });
12234
12467
  };
12235
12468
  var TooltipTrigger = ({
12236
12469
  asChild = true,
@@ -12239,7 +12472,7 @@ var TooltipTrigger = ({
12239
12472
  css: userCss
12240
12473
  }) => {
12241
12474
  const { refs, getReferenceProps, id } = useTooltipCtx();
12242
- const isElement = React47.isValidElement(children);
12475
+ const isElement = React48.isValidElement(children);
12243
12476
  const isDomChild = isElement && typeof children.type === "string";
12244
12477
  if (asChild && isElement && isDomChild) {
12245
12478
  const child = children;
@@ -12253,9 +12486,9 @@ var TooltipTrigger = ({
12253
12486
  child.props?.css || void 0,
12254
12487
  userCss
12255
12488
  ].filter(Boolean);
12256
- return React47.cloneElement(child, { ...merged, css: mergedCss });
12489
+ return React48.cloneElement(child, { ...merged, css: mergedCss });
12257
12490
  }
12258
- return /* @__PURE__ */ jsx53(
12491
+ return /* @__PURE__ */ jsx54(
12259
12492
  "span",
12260
12493
  {
12261
12494
  ref: refs.setReference,
@@ -12291,7 +12524,7 @@ var TooltipContent = ({
12291
12524
  const initial = side === "bottom" ? { opacity: 0, y: -delta, scale: 0.98 } : side === "top" ? { opacity: 0, y: +delta, scale: 0.98 } : side === "left" ? { opacity: 0, x: +delta, scale: 0.98 } : { opacity: 0, x: -delta, scale: 0.98 };
12292
12525
  const exit = initial;
12293
12526
  const transformOrigin = side === "bottom" ? "center top" : side === "top" ? "center bottom" : side === "left" ? "right center" : "left center";
12294
- const tooltipBase = css45({
12527
+ const tooltipBase = css46({
12295
12528
  zIndex: 1300,
12296
12529
  backgroundColor: theme.neutral[900],
12297
12530
  color: theme.neutral[0],
@@ -12306,7 +12539,7 @@ var TooltipContent = ({
12306
12539
  pointerEvents: "auto",
12307
12540
  transformOrigin
12308
12541
  });
12309
- const arrowBase = css45({
12542
+ const arrowBase = css46({
12310
12543
  position: "absolute",
12311
12544
  width: 10,
12312
12545
  height: 10,
@@ -12317,7 +12550,7 @@ var TooltipContent = ({
12317
12550
  });
12318
12551
  const arrowData = middlewareData.arrow;
12319
12552
  const staticSide = { top: "bottom", bottom: "top", left: "right", right: "left" }[side];
12320
- return /* @__PURE__ */ jsx53(FloatingPortal3, { children: /* @__PURE__ */ jsx53(AnimatePresence6, { children: open && /* @__PURE__ */ jsxs32(
12553
+ return /* @__PURE__ */ jsx54(FloatingPortal3, { children: /* @__PURE__ */ jsx54(AnimatePresence6, { children: open && /* @__PURE__ */ jsxs32(
12321
12554
  motion6.div,
12322
12555
  {
12323
12556
  id,
@@ -12339,7 +12572,7 @@ var TooltipContent = ({
12339
12572
  ...getFloatingProps(),
12340
12573
  children: [
12341
12574
  children,
12342
- allowArrow && /* @__PURE__ */ jsx53(
12575
+ allowArrow && /* @__PURE__ */ jsx54(
12343
12576
  "div",
12344
12577
  {
12345
12578
  ref: arrowRef,
@@ -12358,14 +12591,14 @@ var TooltipContent = ({
12358
12591
  };
12359
12592
 
12360
12593
  // src/theme/CssBaseline.tsx
12361
- import { Global, css as css46 } from "@emotion/react";
12362
- import { jsx as jsx54 } from "@emotion/react/jsx-runtime";
12594
+ import { Global, css as css47 } from "@emotion/react";
12595
+ import { jsx as jsx55 } from "@emotion/react/jsx-runtime";
12363
12596
  function CssBaseline() {
12364
12597
  const t = usePlainframeUITheme();
12365
- return /* @__PURE__ */ jsx54(
12598
+ return /* @__PURE__ */ jsx55(
12366
12599
  Global,
12367
12600
  {
12368
- styles: css46`
12601
+ styles: css47`
12369
12602
  *,*::before,*::after{box-sizing:border-box}
12370
12603
  :where(html){-webkit-text-size-adjust:100%;text-size-adjust:100%;scroll-behavior:smooth}
12371
12604
  html,body,#root{height:100%}
@@ -12493,6 +12726,8 @@ export {
12493
12726
  SubMenu,
12494
12727
  SubMenuContent,
12495
12728
  SubMenuTrigger,
12729
+ Swap,
12730
+ SwapItem,
12496
12731
  Switch,
12497
12732
  Tab,
12498
12733
  TabContent,