aporia 0.2.1 → 0.2.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
@@ -2,9 +2,9 @@ var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import t, { useContext, createContext, useId, useState, useCallback, useEffect, useRef, useLayoutEffect, useMemo } from "react";
6
- import { useMotionValue, useSpring, useTransform, motion } from "motion/react";
7
- import { Popover } from "@base-ui/react";
5
+ import t, { useContext, createContext, useId, useState, useCallback, useRef, useLayoutEffect, useEffect, useMemo } from "react";
6
+ import { motion, useMotionValue, useSpring, useTransform } from "motion/react";
7
+ import { Popover, Select } from "@base-ui/react";
8
8
  function Panel({ children, className, ...rest }) {
9
9
  return /* @__PURE__ */ jsx(
10
10
  "div",
@@ -25,6 +25,12 @@ function CategoryDisabledProvider({
25
25
  function useCategoryDisabled() {
26
26
  return useContext(CategoryDisabledContext);
27
27
  }
28
+ const categoryBodyTransition = {
29
+ type: "spring",
30
+ stiffness: 1e3,
31
+ damping: 44,
32
+ mass: 0.28
33
+ };
28
34
  function Category({
29
35
  title,
30
36
  children,
@@ -47,11 +53,26 @@ function Category({
47
53
  },
48
54
  [collapsedProp, onCollapsedChange]
49
55
  );
56
+ const innerRef = useRef(null);
57
+ const [bodyHeightPx, setBodyHeightPx] = useState(0);
58
+ useLayoutEffect(() => {
59
+ const inner = innerRef.current;
60
+ if (!inner) return;
61
+ const measure = () => {
62
+ setBodyHeightPx(inner.scrollHeight);
63
+ };
64
+ measure();
65
+ const ro = new ResizeObserver(measure);
66
+ ro.observe(inner);
67
+ return () => ro.disconnect();
68
+ }, []);
69
+ const openBodyHeight = Math.max(bodyHeightPx, 1);
50
70
  return /* @__PURE__ */ jsxs(
51
71
  "section",
52
72
  {
53
73
  className: ["category", className].filter(Boolean).join(" "),
54
74
  "data-disabled": disabled ? "true" : "false",
75
+ "data-collapsed": collapsed ? "true" : "false",
55
76
  children: [
56
77
  /* @__PURE__ */ jsxs("div", { className: "categoryHeader", children: [
57
78
  /* @__PURE__ */ jsxs("div", { className: "categoryHeaderStart", children: [
@@ -88,7 +109,14 @@ function Category({
88
109
  )
89
110
  }
90
111
  ) }),
91
- /* @__PURE__ */ jsx("h2", { className: "categoryTitle", id: `${bodyId}-label`, children: title })
112
+ /* @__PURE__ */ jsx(
113
+ "h2",
114
+ {
115
+ className: "categoryTitle",
116
+ id: `${bodyId}-label`,
117
+ children: title
118
+ }
119
+ )
92
120
  ] }),
93
121
  onDisabledChange ? /* @__PURE__ */ jsx(
94
122
  "button",
@@ -105,15 +133,40 @@ function Category({
105
133
  ) : null
106
134
  ] }),
107
135
  /* @__PURE__ */ jsx(CategoryDisabledProvider, { value: disabled, children: /* @__PURE__ */ jsx(
108
- "div",
136
+ motion.div,
109
137
  {
110
138
  id: bodyId,
111
- className: "categoryBody sliderGroup",
139
+ className: "categoryBody",
112
140
  role: "region",
113
141
  "aria-labelledby": `${bodyId}-label`,
114
- hidden: collapsed,
115
142
  "aria-hidden": collapsed,
116
- children
143
+ initial: false,
144
+ animate: {
145
+ height: collapsed ? 0 : openBodyHeight,
146
+ marginTop: collapsed ? -8 : 0,
147
+ opacity: collapsed ? 0 : 1
148
+ },
149
+ transition: {
150
+ height: categoryBodyTransition,
151
+ marginTop: categoryBodyTransition,
152
+ // Fade out quickly while collapsing so controls don’t peek; gentler fade-in on expand.
153
+ opacity: collapsed ? { duration: 0.09, ease: "easeIn" } : { duration: 0.15, ease: "easeOut" }
154
+ },
155
+ style: {
156
+ /* visible so SliderRow edge stretch (width/margin motion) isn’t clipped; collapse hides via height + opacity + inert */
157
+ overflow: "visible",
158
+ minHeight: 0,
159
+ boxSizing: "border-box"
160
+ },
161
+ inert: collapsed,
162
+ children: /* @__PURE__ */ jsx(
163
+ "div",
164
+ {
165
+ ref: innerRef,
166
+ className: "categoryBodyInner sliderGroup",
167
+ children
168
+ }
169
+ )
117
170
  }
118
171
  ) })
119
172
  ]
@@ -451,9 +504,6 @@ function useSliderOverlapDebugEnabled() {
451
504
  const ThemeContext = createContext(null);
452
505
  function ThemeProvider({ children }) {
453
506
  const theme = "dark";
454
- useEffect(() => {
455
- document.documentElement.dataset.theme = theme;
456
- }, [theme]);
457
507
  return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: { theme }, children });
458
508
  }
459
509
  function useTheme() {
@@ -2101,6 +2151,91 @@ function ToggleRow({ label, checked, onChange, disabled: disabledProp }) {
2101
2151
  }
2102
2152
  ) });
2103
2153
  }
2154
+ function SelectRow({
2155
+ label,
2156
+ options,
2157
+ value,
2158
+ onChange,
2159
+ placeholder = "Choose…",
2160
+ disabled: disabledProp,
2161
+ name
2162
+ }) {
2163
+ const categoryDisabled = useCategoryDisabled();
2164
+ const disabled = Boolean(disabledProp || categoryDisabled);
2165
+ const [menuOpen, setMenuOpen] = useState(false);
2166
+ const wrapRef = useRef(null);
2167
+ const [anchorWidth, setAnchorWidth] = useState(0);
2168
+ useLayoutEffect(() => {
2169
+ const el = wrapRef.current;
2170
+ if (!el) return;
2171
+ const ro = new ResizeObserver(() => {
2172
+ setAnchorWidth(el.offsetWidth);
2173
+ });
2174
+ ro.observe(el);
2175
+ setAnchorWidth(el.offsetWidth);
2176
+ return () => ro.disconnect();
2177
+ }, []);
2178
+ const portalStyle = anchorWidth > 0 ? { "--select-anchor-width": `${anchorWidth}px` } : void 0;
2179
+ const items = useMemo(
2180
+ () => Object.fromEntries(options.map((o) => [o.value, o.label])),
2181
+ [options]
2182
+ );
2183
+ return /* @__PURE__ */ jsx(
2184
+ "div",
2185
+ {
2186
+ ref: wrapRef,
2187
+ className: "selectRowWrap",
2188
+ "data-disabled": disabled ? "true" : "false",
2189
+ children: /* @__PURE__ */ jsxs(
2190
+ Select.Root,
2191
+ {
2192
+ name,
2193
+ items,
2194
+ value,
2195
+ onValueChange: (next) => {
2196
+ if (next != null) onChange(next);
2197
+ },
2198
+ onOpenChange: (open) => setMenuOpen(open),
2199
+ disabled,
2200
+ modal: false,
2201
+ children: [
2202
+ /* @__PURE__ */ jsxs(Select.Trigger, { className: "selectCard", "data-menu-open": menuOpen ? "true" : "false", children: [
2203
+ /* @__PURE__ */ jsx("span", { className: "selectLabel", children: label }),
2204
+ /* @__PURE__ */ jsxs("span", { className: "selectValueZone", children: [
2205
+ /* @__PURE__ */ jsx(Select.Value, { placeholder, className: "selectValue" }),
2206
+ /* @__PURE__ */ jsx(Select.Icon, { className: "selectIcon", "aria-hidden": true, children: /* @__PURE__ */ jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", className: "selectChevronSvg", children: /* @__PURE__ */ jsx(
2207
+ "path",
2208
+ {
2209
+ d: "M3 4.5L6 7.5L9 4.5",
2210
+ fill: "none",
2211
+ stroke: "currentColor",
2212
+ strokeWidth: "1.5",
2213
+ strokeLinecap: "round",
2214
+ strokeLinejoin: "round"
2215
+ }
2216
+ ) }) })
2217
+ ] })
2218
+ ] }),
2219
+ /* @__PURE__ */ jsx(Select.Portal, { className: "selectPortal", style: portalStyle, children: /* @__PURE__ */ jsx(
2220
+ Select.Positioner,
2221
+ {
2222
+ className: "selectPositioner",
2223
+ style: portalStyle,
2224
+ positionMethod: "fixed",
2225
+ side: "bottom",
2226
+ align: "end",
2227
+ sideOffset: 6,
2228
+ alignItemWithTrigger: false,
2229
+ collisionAvoidance: { side: "flip", align: "shift", fallbackAxisSide: "none" },
2230
+ children: /* @__PURE__ */ jsx(Select.Popup, { className: "selectPopup", children: /* @__PURE__ */ jsx(Select.List, { className: "selectList", children: options.map((opt) => /* @__PURE__ */ jsx(Select.Item, { value: opt.value, className: "selectItem", children: /* @__PURE__ */ jsx(Select.ItemText, { className: "selectItemText", children: opt.label }) }, opt.value)) }) })
2231
+ }
2232
+ ) })
2233
+ ]
2234
+ }
2235
+ )
2236
+ }
2237
+ );
2238
+ }
2104
2239
  function generateAestheticGradient(stopCount) {
2105
2240
  const baseHue = Math.random() * 360;
2106
2241
  const hueShift = 25 + Math.random() * 35;
@@ -2402,6 +2537,7 @@ export {
2402
2537
  GradientPicker,
2403
2538
  GradientRow,
2404
2539
  Panel,
2540
+ SelectRow,
2405
2541
  SliderOverlapDebugProvider,
2406
2542
  SliderRow,
2407
2543
  SwatchPopover,