@zovaris/sephiro 0.8.0 → 0.9.0

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
@@ -365,7 +365,7 @@ function Spinner({ size = "md", label, className, ...props }) {
365
365
  }
366
366
  //#endregion
367
367
  //#region src/atoms/Button/index.tsx
368
- function Button({ variant = "secondary", size = "md", loading = false, disabled, className, type = "button", children, onClick, "aria-busy": ariaBusy, "aria-disabled": ariaDisabled, ...props }) {
368
+ function Button({ variant = "secondary", size = "md", density = "default", motion = "lift", loading = false, disabled, className, type = "button", children, onClick, "aria-busy": ariaBusy, "aria-disabled": ariaDisabled, ...props }) {
369
369
  const handleClick = (event) => {
370
370
  if (loading) {
371
371
  event.preventDefault();
@@ -378,6 +378,8 @@ function Button({ variant = "secondary", size = "md", loading = false, disabled,
378
378
  className: cn("sph-button", className),
379
379
  "data-variant": variant,
380
380
  "data-size": size,
381
+ "data-density": density,
382
+ "data-motion": motion,
381
383
  "data-loading": loading || void 0,
382
384
  disabled,
383
385
  ...node(props),
@@ -422,7 +424,7 @@ function Checkbox({ label, size = "md", invalid = false, className, ...props })
422
424
  }
423
425
  //#endregion
424
426
  //#region src/atoms/IconButton/index.tsx
425
- function IconButton({ icon, label, size = "md", variant = "ghost", loading = false, disabled, className, type = "button", onClick, ...props }) {
427
+ function IconButton({ icon, label, size = "md", density = "default", variant = "ghost", loading = false, disabled, className, type = "button", onClick, ...props }) {
426
428
  const handleClick = (event) => {
427
429
  if (loading) {
428
430
  event.preventDefault();
@@ -435,9 +437,10 @@ function IconButton({ icon, label, size = "md", variant = "ghost", loading = fal
435
437
  type,
436
438
  className: cn("sph-icon-button", className),
437
439
  "data-size": size,
440
+ "data-density": density,
438
441
  "data-variant": variant,
439
442
  "data-loading": loading || void 0,
440
- "aria-label": label,
443
+ "aria-label": props["aria-label"] ?? label,
441
444
  "aria-busy": loading ? true : props["aria-busy"],
442
445
  "aria-disabled": loading ? true : props["aria-disabled"],
443
446
  disabled,
@@ -1364,11 +1367,6 @@ function matchText(text, query) {
1364
1367
  indexes
1365
1368
  };
1366
1369
  }
1367
- /**
1368
- * Filters `items` with `query`, preserving their original order.
1369
- * `label` is matched first (its indexes drive highlighting); `keywords`
1370
- * are a fallback that keeps an item visible without highlightable ranges.
1371
- */
1372
1370
  function filterItems(items, query, read) {
1373
1371
  const trimmed = query.trim();
1374
1372
  if (trimmed.length === 0) return items.map((item) => ({
@@ -1393,6 +1391,13 @@ function filterItems(items, query, read) {
1393
1391
  }
1394
1392
  return results;
1395
1393
  }
1394
+ function filterItemsWith(items, query, read, filter) {
1395
+ if (!filter) return filterItems(items, query, read);
1396
+ return items.filter((item) => filter(item, query)).map((item) => ({
1397
+ item,
1398
+ indexes: matchText(read(item).label, query)?.indexes ?? []
1399
+ }));
1400
+ }
1396
1401
  //#endregion
1397
1402
  //#region src/lib/highlight.tsx
1398
1403
  /**
@@ -2309,7 +2314,10 @@ function Field({ label, htmlFor, description, message, messageType = "hint", req
2309
2314
  const descriptionId = description ? `${generatedId}-description` : void 0;
2310
2315
  const messageId = message ? `${generatedId}-message` : void 0;
2311
2316
  const describedBy = [descriptionId, messageId].filter(Boolean).join(" ");
2312
- const control = isValidElement(children) ? cloneElement(children, {
2317
+ const isControl = isValidElement(children);
2318
+ const controlId = (isControl ? children.props.id : void 0) ?? htmlFor ?? (isControl ? `${generatedId}-control` : void 0);
2319
+ const control = isControl ? cloneElement(children, {
2320
+ id: controlId,
2313
2321
  "aria-describedby": [children.props["aria-describedby"], describedBy].filter(Boolean).join(" ") || void 0,
2314
2322
  "aria-required": children.props["aria-required"] ?? (required || void 0),
2315
2323
  "aria-invalid": children.props["aria-invalid"] ?? (messageType === "error" && messageId ? true : void 0)
@@ -2319,7 +2327,7 @@ function Field({ label, htmlFor, description, message, messageType = "hint", req
2319
2327
  children: [
2320
2328
  label !== void 0 && /* @__PURE__ */ jsxs("label", {
2321
2329
  className: "sph-field__label",
2322
- htmlFor,
2330
+ htmlFor: htmlFor ?? controlId,
2323
2331
  children: [/* @__PURE__ */ jsx("span", { children: node(label) }), required && /* @__PURE__ */ jsx("span", {
2324
2332
  className: "sph-field__required",
2325
2333
  children: "Required"
@@ -4231,7 +4239,6 @@ function Chart({ categories, series, variant = "line", height = 160, smooth = fa
4231
4239
  }
4232
4240
  //#endregion
4233
4241
  //#region src/organisms/CommandPalette/index.tsx
4234
- /** Re-runs a CSS animation by detaching, reflowing, and re-attaching it. */
4235
4242
  function replay(element, className) {
4236
4243
  if (!element) return;
4237
4244
  element.classList.remove(className);
@@ -4256,7 +4263,7 @@ function resolveActive(options, wanted) {
4256
4263
  for (let index = 0; index < start; index += 1) if (enabled(index)) return index;
4257
4264
  return start;
4258
4265
  }
4259
- function CommandPalette({ open, onOpenChange, items, onSelect, placeholder = "Type a command or search…", emptyMessage = "No results.", homeLabel = "Home", ariaLabel = "Command palette", hotkey = false, className }) {
4266
+ function CommandPalette({ open, onOpenChange, items, onSelect, placeholder = "Type a command or search…", emptyMessage = "No results.", homeLabel = "Home", ariaLabel = "Command palette", hotkey = false, className, filter }) {
4260
4267
  const listId = useId();
4261
4268
  const rootRef = useRef(null);
4262
4269
  const panelRef = useRef(null);
@@ -4275,12 +4282,13 @@ function CommandPalette({ open, onOpenChange, items, onSelect, placeholder = "Ty
4275
4282
  const visible = present && portaled;
4276
4283
  useFocusTrap(rootRef, visible, inputRef);
4277
4284
  const levelItems = path.length > 0 ? path[path.length - 1]?.children ?? [] : items;
4285
+ const hasNestedLevels = items.some((item) => (item.children?.length ?? 0) > 0);
4278
4286
  const { sections, options } = useMemo(() => {
4279
4287
  const read = (item) => ({
4280
4288
  label: readableLabel(item),
4281
4289
  keywords: [item.keywords ?? "", ...(item.children ?? []).map((child) => readableLabel(child))].filter(Boolean).join(" ")
4282
4290
  });
4283
- const filtered = filterItems(levelItems, query, read);
4291
+ const filtered = filterItemsWith(levelItems, query, read, filter);
4284
4292
  const ungrouped = filtered.filter((entry) => entry.item.group === void 0);
4285
4293
  const grouped = [...new Set(filtered.map((entry) => entry.item.group).filter((name) => name !== void 0))].map((name) => ({
4286
4294
  heading: name,
@@ -4305,6 +4313,7 @@ function CommandPalette({ open, onOpenChange, items, onSelect, placeholder = "Ty
4305
4313
  options: built.flatMap((s) => s.entries)
4306
4314
  };
4307
4315
  }, [
4316
+ filter,
4308
4317
  levelItems,
4309
4318
  listId,
4310
4319
  query
@@ -4502,7 +4511,7 @@ function CommandPalette({ open, onOpenChange, items, onSelect, placeholder = "Ty
4502
4511
  ref: panelRef,
4503
4512
  className: "sph-palette__panel",
4504
4513
  children: [
4505
- /* @__PURE__ */ jsxs("nav", {
4514
+ hasNestedLevels && /* @__PURE__ */ jsxs("nav", {
4506
4515
  className: "sph-palette__crumbs",
4507
4516
  "aria-label": "Breadcrumb",
4508
4517
  children: [
@@ -5163,8 +5172,38 @@ function Resizable({ panes, direction = "horizontal", sizes, defaultSizes, onSiz
5163
5172
  });
5164
5173
  }
5165
5174
  //#endregion
5175
+ //#region src/organisms/SidePanel/index.tsx
5176
+ function SidePanel({ children, side = "left", width = 280, collapsed, defaultCollapsed = false, onCollapsedChange, peek = false, className, style, ...props }) {
5177
+ const [uncontrolled, setUncontrolled] = useState(defaultCollapsed);
5178
+ const isCollapsed = collapsed ?? uncontrolled;
5179
+ const setCollapsed = (next) => {
5180
+ setUncontrolled(next);
5181
+ onCollapsedChange?.(next);
5182
+ };
5183
+ const state = {
5184
+ collapsed: isCollapsed,
5185
+ setCollapsed,
5186
+ toggle: () => setCollapsed(!isCollapsed)
5187
+ };
5188
+ return /* @__PURE__ */ jsx("aside", {
5189
+ ...node(props),
5190
+ className: cn("sph-side-panel", className),
5191
+ style: {
5192
+ ...style,
5193
+ "--sph-side-panel-width": typeof width === "number" ? `${width}px` : width
5194
+ },
5195
+ "data-side": side,
5196
+ "data-collapsed": isCollapsed || void 0,
5197
+ "data-peek": isCollapsed && peek || void 0,
5198
+ children: /* @__PURE__ */ jsx("div", {
5199
+ className: "sph-side-panel__inner",
5200
+ children: node(typeof children === "function" ? children(state) : children)
5201
+ })
5202
+ });
5203
+ }
5204
+ //#endregion
5166
5205
  //#region src/organisms/Sidebar/index.tsx
5167
- function Sidebar({ sections, value, defaultValue, onSelect, header, footer, collapsible = false, collapsed, defaultCollapsed = false, onCollapsedChange, ariaLabel = "Primary", className, ...props }) {
5206
+ function Sidebar({ sections, value, defaultValue, onSelect, header, footer, side = "left", collapsible = false, collapsed, collapsedMode = "rail", defaultCollapsed = collapsedMode !== "rail", onCollapsedChange, ariaLabel = "Primary", className, ...props }) {
5168
5207
  const listId = useId();
5169
5208
  const [uncontrolled, setUncontrolled] = useState(defaultCollapsed);
5170
5209
  const isCollapsed = collapsed ?? uncontrolled;
@@ -5174,10 +5213,16 @@ function Sidebar({ sections, value, defaultValue, onSelect, header, footer, coll
5174
5213
  setUncontrolled(next);
5175
5214
  onCollapsedChange?.(next);
5176
5215
  };
5216
+ const expandChevron = side === "left" ? "»" : "«";
5217
+ const collapseChevron = side === "left" ? "«" : "»";
5218
+ const showItemTitle = isCollapsed && collapsedMode !== "hover";
5177
5219
  return /* @__PURE__ */ jsxs("aside", {
5178
5220
  ...node(props),
5179
5221
  className: cn("sph-sidebar", className),
5222
+ "data-side": side,
5180
5223
  "data-collapsed": isCollapsed || void 0,
5224
+ "data-collapsed-mode": collapsedMode,
5225
+ "data-rail": isCollapsed || void 0,
5181
5226
  children: [
5182
5227
  header !== void 0 && /* @__PURE__ */ jsx("div", {
5183
5228
  className: "sph-sidebar__header",
@@ -5200,7 +5245,7 @@ function Sidebar({ sections, value, defaultValue, onSelect, header, footer, coll
5200
5245
  "data-active": isActive || void 0,
5201
5246
  "aria-current": isActive ? "page" : void 0,
5202
5247
  disabled: item.disabled,
5203
- title: isCollapsed && typeof item.label === "string" ? item.label : void 0,
5248
+ title: showItemTitle && typeof item.label === "string" ? item.label : void 0,
5204
5249
  onClick: () => onSelect?.(item.value),
5205
5250
  children: [
5206
5251
  item.icon !== void 0 && /* @__PURE__ */ jsx("span", {
@@ -5238,7 +5283,7 @@ function Sidebar({ sections, value, defaultValue, onSelect, header, footer, coll
5238
5283
  onClick: toggleCollapsed,
5239
5284
  children: /* @__PURE__ */ jsx("span", {
5240
5285
  "aria-hidden": "true",
5241
- children: isCollapsed ? "»" : "«"
5286
+ children: isCollapsed ? expandChevron : collapseChevron
5242
5287
  })
5243
5288
  })]
5244
5289
  })
@@ -6241,7 +6286,7 @@ function segmentTarget(options, index, key) {
6241
6286
  }
6242
6287
  return -1;
6243
6288
  }
6244
- function SegmentedControl({ options, ariaLabel, value, defaultValue, onValueChange, size = "md", fullWidth = false, disabled = false, className }) {
6289
+ function SegmentedControl({ options, ariaLabel, value, defaultValue, onValueChange, size = "md", density = "default", fullWidth = false, disabled = false, className }) {
6245
6290
  const generatedId = useId();
6246
6291
  const [uncontrolledValue, setUncontrolledValue] = useState(() => defaultValue ?? options.find((option) => !option.disabled)?.value ?? "");
6247
6292
  const activeValue = value ?? uncontrolledValue;
@@ -6270,6 +6315,7 @@ function SegmentedControl({ options, ariaLabel, value, defaultValue, onValueChan
6270
6315
  "aria-disabled": disabled || void 0,
6271
6316
  className: cn("sph-segmented-control", className),
6272
6317
  "data-size": size,
6318
+ "data-density": density,
6273
6319
  "data-full-width": fullWidth || void 0,
6274
6320
  "data-disabled": disabled || void 0,
6275
6321
  style,
@@ -7462,6 +7508,6 @@ function ChatScroller({ children, itemCount, newCount, threshold = 48, ariaLabel
7462
7508
  });
7463
7509
  }
7464
7510
  //#endregion
7465
- export { Accordion, Alert, AnimatedNumber, Attachment, Avatar, AvatarGroup, Badge, Breadcrumb, Button, Calendar, Card, Chart, ChatScroller, Checkbox, Citation, Collapsible, Combobox, CommandPalette, ContextMenu, Delta, Dialog, Drawer, EmptyState, Field, FieldMessage, HoldButton, HoverCard, IconButton, Input, Kbd, MagneticDropzone, Menu, Menubar, MetadataList, Notice, NumberInput, OTPInput, OverflowList, Pagination, PlanCard, Popover, Progress, QuestionCard, RadioGroup, ReasoningSteps, Resizable, Reveal, ScrollArea, SegmentedControl, Select, Separator, Sidebar, Skeleton, Slider, Spinner, Stat, StatGroup, StatusMark, Stepper, StreamingText, Surface, Table, Tabs, TaskList, Textarea, Timeline, Timestamp, Toast, ToastViewport, Toggle, ToolCalls, Toolbar, Tooltip, TooltipGroup, describeDropzoneResult, motionDurationMs, parseDurationMs, toast, usePresence, validateDropzoneFiles };
7511
+ export { Accordion, Alert, AnimatedNumber, Attachment, Avatar, AvatarGroup, Badge, Breadcrumb, Button, Calendar, Card, Chart, ChatScroller, Checkbox, Citation, Collapsible, Combobox, CommandPalette, ContextMenu, Delta, Dialog, Drawer, EmptyState, Field, FieldMessage, HoldButton, HoverCard, IconButton, Input, Kbd, MagneticDropzone, Menu, Menubar, MetadataList, Notice, NumberInput, OTPInput, OverflowList, Pagination, PlanCard, Popover, Progress, QuestionCard, RadioGroup, ReasoningSteps, Resizable, Reveal, ScrollArea, SegmentedControl, Select, Separator, SidePanel, Sidebar, Skeleton, Slider, Spinner, Stat, StatGroup, StatusMark, Stepper, StreamingText, Surface, Table, Tabs, TaskList, Textarea, Timeline, Timestamp, Toast, ToastViewport, Toggle, ToolCalls, Toolbar, Tooltip, TooltipGroup, describeDropzoneResult, motionDurationMs, parseDurationMs, toast, usePresence, validateDropzoneFiles };
7466
7512
 
7467
7513
  //# sourceMappingURL=index.js.map