prime-ui-kit 0.21.0 → 0.21.2

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.
Files changed (46) hide show
  1. package/dist/chunks/{chunk-S27VR4ON.js → chunk-7JYPFRZ3.js} +77 -23
  2. package/dist/chunks/{chunk-S4H2ZKWJ.js → chunk-ME4VEAQ5.js} +40 -13
  3. package/dist/chunks/{chunk-IVS3J7AS.js → chunk-SQGPQOUO.js} +1 -1
  4. package/dist/chunks/{chunk-QFHE5GKW.js → chunk-T7IEJSTH.js} +569 -556
  5. package/dist/chunks/{chunk-6L7VWEY6.js → chunk-VQ3UCVDV.js} +2 -2
  6. package/dist/color-picker.js +3 -3
  7. package/dist/components/message/Message.d.ts +2 -2
  8. package/dist/components/scroll-container/ScrollContainer.d.ts +1 -1
  9. package/dist/icon-set.d.ts +1 -0
  10. package/dist/icon-set.js +4 -2
  11. package/dist/icons/glyphs/app-window.d.ts +2 -0
  12. package/dist/icons/registry.d.ts +2 -0
  13. package/dist/index.css +1 -1
  14. package/dist/index.js +3 -3
  15. package/dist/internal/overlay/DialogParts.d.ts +1 -1
  16. package/dist/internal/selectionIndicator.d.ts +9 -3
  17. package/dist/layout/page/Page.d.ts +1 -1
  18. package/dist/skill/api-contract.md +1 -1
  19. package/dist/skill/checklist.md +1 -0
  20. package/dist/skill/choosing.md +3 -2
  21. package/dist/skill/composition.md +58 -1
  22. package/dist/skill/layouts.md +1 -0
  23. package/dist/skill/reference/components/data-table/COMPONENT.md +1 -0
  24. package/dist/skill/reference/components/message/COMPONENT.md +6 -5
  25. package/dist/skill/reference/components/message/examples/bot-actions.tsx +6 -2
  26. package/dist/skill/reference/components/scroll-container/COMPONENT.md +5 -5
  27. package/dist/skill/reference/components/scroll-container/examples/overscroll.tsx +2 -2
  28. package/dist/skill/reference/components/tabs/COMPONENT.md +1 -1
  29. package/dist/skill/reference/icon-set.ts +1 -0
  30. package/dist/skill/reference/layout/app-shell/COMPONENT.md +1 -1
  31. package/dist/skill/reference/layout/page/COMPONENT.md +9 -6
  32. package/dist/skill/reference/layout/page/examples/router.tsx +124 -0
  33. package/dist/skill/reference/layout/page/examples/tools.tsx +12 -22
  34. package/dist/skill/reference/layout/sidebar/COMPONENT.md +4 -1
  35. package/package.json +1 -1
  36. package/src/components/data-table/COMPONENT.md +1 -0
  37. package/src/components/message/COMPONENT.md +6 -5
  38. package/src/components/message/examples/bot-actions.tsx +6 -2
  39. package/src/components/scroll-container/COMPONENT.md +5 -5
  40. package/src/components/scroll-container/examples/overscroll.tsx +2 -2
  41. package/src/components/tabs/COMPONENT.md +1 -1
  42. package/src/layout/app-shell/COMPONENT.md +1 -1
  43. package/src/layout/page/COMPONENT.md +9 -6
  44. package/src/layout/page/examples/router.tsx +124 -0
  45. package/src/layout/page/examples/tools.tsx +12 -22
  46. package/src/layout/sidebar/COMPONENT.md +4 -1
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {
4
4
  Activity,
5
+ AppWindow,
5
6
  ArrowDown,
6
7
  ArrowUp,
7
8
  ArrowUpDown,
@@ -139,7 +140,7 @@ import {
139
140
  useIconRoot,
140
141
  useOptionalControlSize,
141
142
  usePresence
142
- } from "./chunk-QFHE5GKW.js";
143
+ } from "./chunk-T7IEJSTH.js";
143
144
 
144
145
  // src/components/scroll-container/ScrollContainer.tsx
145
146
  import * as React9 from "react";
@@ -1208,7 +1209,7 @@ var axisClass = {
1208
1209
  function ScrollContainer({
1209
1210
  as: Component = "div",
1210
1211
  axis = "vertical",
1211
- overscrollBehavior = "contain",
1212
+ overscrollBehavior = "auto",
1212
1213
  edges = "fade",
1213
1214
  scrollbar = "thin",
1214
1215
  lock = false,
@@ -2276,7 +2277,10 @@ function FloatingPanel({
2276
2277
  }
2277
2278
  };
2278
2279
  const panelRef = sheet ? ref : mergedRef;
2279
- const panel = scroll ? /* @__PURE__ */ jsx7(ScrollContainer, { ...props, edges: "shadow", ref: panelRef, children }) : /* @__PURE__ */ jsx7("div", { ...props, ref: panelRef, children });
2280
+ const panel = scroll ? (
2281
+ // An open layer: a touch scroll at its end never moves the page (the wheel: `useContainScroll`).
2282
+ /* @__PURE__ */ jsx7(ScrollContainer, { ...props, edges: "shadow", overscrollBehavior: "contain", ref: panelRef, children })
2283
+ ) : /* @__PURE__ */ jsx7("div", { ...props, ref: panelRef, children });
2280
2284
  return /* @__PURE__ */ jsx7(Portal, { children: /* @__PURE__ */ jsx7(LayerProvider, { value: floating.layer, children: /* @__PURE__ */ jsx7(SurfaceDepthProvider, { value: "floating", children: /* @__PURE__ */ jsx7(ControlSizeProvider, { value: size, children: sheet ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
2281
2285
  /* @__PURE__ */ jsx7(
2282
2286
  "div",
@@ -2817,6 +2821,8 @@ var iconRegistry = {
2817
2821
  "action.login": LogIn,
2818
2822
  "action.logout": LogOut,
2819
2823
  "action.more": Ellipsis,
2824
+ /** Open a page of this product (a bot key's web app); `action.externalLink` leaves it. */
2825
+ "action.openApp": AppWindow,
2820
2826
  "action.pause": Pause,
2821
2827
  /** Pin a message or an item to the top. */
2822
2828
  "action.pin": Pin,
@@ -3868,16 +3874,39 @@ function splitChange(from, to) {
3868
3874
  function digitsOnly(a, b) {
3869
3875
  return a.replace(/\d/g, "") === b.replace(/\d/g, "");
3870
3876
  }
3871
- function letters(text, kind) {
3872
- return [...text].map((char, i) => /* @__PURE__ */ jsx14(
3873
- "span",
3874
- {
3875
- className: cx(MorphText_default.letter, kind === "in" ? MorphText_default.letterIn : MorphText_default.letterOut),
3876
- style: { "--morph-i": i },
3877
- children: char
3878
- },
3879
- i
3880
- ));
3877
+ function letters(text, kind, poses) {
3878
+ return [...text].map((char, i) => {
3879
+ const pose = poses?.[i];
3880
+ const style = { "--morph-i": i };
3881
+ if (pose) {
3882
+ style["--morph-opacity"] = pose.opacity;
3883
+ style["--morph-y"] = `${pose.y}px`;
3884
+ }
3885
+ return /* @__PURE__ */ jsx14(
3886
+ "span",
3887
+ {
3888
+ className: cx(MorphText_default.letter, kind === "in" ? MorphText_default.letterIn : MorphText_default.letterOut),
3889
+ style,
3890
+ children: char
3891
+ },
3892
+ i
3893
+ );
3894
+ });
3895
+ }
3896
+ function readPoses(layer) {
3897
+ if (!layer) return [];
3898
+ return Array.from(layer.children, (letter) => {
3899
+ const computed = getComputedStyle(letter);
3900
+ const opacity = Number.parseFloat(computed.opacity);
3901
+ if (Number.isNaN(opacity)) return void 0;
3902
+ const transform = computed.transform;
3903
+ const y = transform && transform !== "none" && typeof DOMMatrixReadOnly === "function" ? new DOMMatrixReadOnly(transform).m42 : 0;
3904
+ return { opacity, y };
3905
+ });
3906
+ }
3907
+ function posesOf(label, running, layerPoses) {
3908
+ const head = [...splitChange(running.from, running.to).prefix].length;
3909
+ return [...label].map((_, i) => layerPoses[i - head]);
3881
3910
  }
3882
3911
  function settleMs(text) {
3883
3912
  const base = readCssDurationMs("--prime-motion-duration-base");
@@ -3888,6 +3917,8 @@ function MorphText({ children: text, className }) {
3888
3917
  const rootRef = React36.useRef(null);
3889
3918
  const segmentRef = React36.useRef(null);
3890
3919
  const sizerRef = React36.useRef(null);
3920
+ const outLayerRef = React36.useRef(null);
3921
+ const inLayerRef = React36.useRef(null);
3891
3922
  const prevText = React36.useRef(null);
3892
3923
  const restWidth = React36.useRef(null);
3893
3924
  const nextId = React36.useRef(0);
@@ -3904,9 +3935,24 @@ function MorphText({ children: text, className }) {
3904
3935
  return;
3905
3936
  }
3906
3937
  const running = morphRef.current;
3907
- const width = running ? root.getBoundingClientRect().width : restWidth.current?.width ?? 0;
3908
3938
  nextId.current += 1;
3909
- setMorph({ id: nextId.current, from: running ? running.to : prev, to: text, width });
3939
+ if (!running) {
3940
+ setMorph({ id: nextId.current, from: prev, to: text, width: restWidth.current?.width ?? 0 });
3941
+ return;
3942
+ }
3943
+ const from = running.to;
3944
+ const change2 = splitChange(from, text);
3945
+ const head = [...change2.prefix].length;
3946
+ const arriving = posesOf(from, running, readPoses(inLayerRef.current));
3947
+ const leaving = posesOf(running.from, running, readPoses(outLayerRef.current));
3948
+ setMorph({
3949
+ id: nextId.current,
3950
+ from,
3951
+ to: text,
3952
+ width: root.getBoundingClientRect().width,
3953
+ outPoses: arriving.slice(head, head + [...change2.out].length),
3954
+ inPoses: text === running.from ? leaving.slice(head, head + [...change2.in].length) : void 0
3955
+ });
3910
3956
  }, [text]);
3911
3957
  const change = morph ? splitChange(morph.from, morph.to) : null;
3912
3958
  React36.useLayoutEffect(() => {
@@ -3916,13 +3962,13 @@ function MorphText({ children: text, className }) {
3916
3962
  const sizer = sizerRef.current;
3917
3963
  if (!root || !segment || !sizer) return;
3918
3964
  const target = sizer.getBoundingClientRect().width;
3919
- const still = root.getBoundingClientRect().width - target;
3965
+ const still = root.getBoundingClientRect().width - segment.getBoundingClientRect().width;
3920
3966
  const from = Math.max(0, morph.width - still);
3921
- if (target !== from) {
3922
- segment.style.width = `${from}px`;
3923
- segment.getBoundingClientRect();
3924
- segment.style.width = `${target}px`;
3925
- }
3967
+ segment.style.transition = "none";
3968
+ segment.style.width = `${from}px`;
3969
+ segment.getBoundingClientRect();
3970
+ segment.style.transition = "";
3971
+ segment.style.width = `${target}px`;
3926
3972
  const changed = splitChange(morph.from, morph.to);
3927
3973
  const longest = changed.in.length > changed.out.length ? changed.in : changed.out;
3928
3974
  const timer = window.setTimeout(() => setMorph(null), settleMs(longest));
@@ -3939,8 +3985,16 @@ function MorphText({ children: text, className }) {
3939
3985
  /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: change.prefix }),
3940
3986
  /* @__PURE__ */ jsxs8("span", { ref: segmentRef, className: MorphText_default.segment, "aria-hidden": "true", children: [
3941
3987
  /* @__PURE__ */ jsx14("span", { ref: sizerRef, className: MorphText_default.sizer, children: change.in }),
3942
- /* @__PURE__ */ jsx14("span", { className: cx(MorphText_default.layer, MorphText_default.layerOut), children: letters(change.out, "out") }, `out-${morph.id}`),
3943
- /* @__PURE__ */ jsx14("span", { className: cx(MorphText_default.layer, MorphText_default.layerIn), children: letters(change.in, "in") }, `in-${morph.id}`)
3988
+ /* @__PURE__ */ jsx14(
3989
+ "span",
3990
+ {
3991
+ ref: outLayerRef,
3992
+ className: cx(MorphText_default.layer, MorphText_default.layerOut),
3993
+ children: letters(change.out, "out", morph.outPoses)
3994
+ },
3995
+ `out-${morph.id}`
3996
+ ),
3997
+ /* @__PURE__ */ jsx14("span", { ref: inLayerRef, className: cx(MorphText_default.layer, MorphText_default.layerIn), children: letters(change.in, "in", morph.inPoses) }, `in-${morph.id}`)
3944
3998
  ] }),
3945
3999
  /* @__PURE__ */ jsx14("span", { "aria-hidden": "true", children: change.suffix }),
3946
4000
  /* @__PURE__ */ jsx14(VisuallyHidden, { children: morph.to })
@@ -183,7 +183,7 @@ import {
183
183
  useTextParts,
184
184
  visuallyHiddenClass,
185
185
  zonedParts
186
- } from "./chunk-S27VR4ON.js";
186
+ } from "./chunk-7JYPFRZ3.js";
187
187
  import {
188
188
  COMPACT_QUERY,
189
189
  ControlSizeProvider,
@@ -206,7 +206,7 @@ import {
206
206
  useHostTier,
207
207
  useOptionalControlSize,
208
208
  usePresence
209
- } from "./chunk-QFHE5GKW.js";
209
+ } from "./chunk-T7IEJSTH.js";
210
210
 
211
211
  // src/layout/app-shell/AppShell.tsx
212
212
  import * as React from "react";
@@ -280,7 +280,6 @@ function AppShellMain({ className, children, ...rest }) {
280
280
  as: "main",
281
281
  axis: "vertical",
282
282
  edges: "none",
283
- overscrollBehavior: "contain",
284
283
  className: cx(AppShell_default.main, className),
285
284
  children
286
285
  }
@@ -422,9 +421,11 @@ function setFlag(element, name, on) {
422
421
  else element.removeAttribute(name);
423
422
  }
424
423
  function placeIndicator(indicator, target, animate) {
424
+ const visible = indicator.hasAttribute("data-visible");
425
425
  if (!target) {
426
- setFlag(indicator, "data-visible", false);
426
+ setFlag(indicator, "data-fade", animate && visible);
427
427
  setFlag(indicator, "data-animate", false);
428
+ setFlag(indicator, "data-visible", false);
428
429
  return;
429
430
  }
430
431
  const left = `${target.offsetLeft}px`;
@@ -433,12 +434,14 @@ function placeIndicator(indicator, target, animate) {
433
434
  const height = `${target.offsetHeight}px`;
434
435
  const { style } = indicator;
435
436
  if (style.left !== left || style.top !== top || style.width !== width || style.height !== height) {
436
- setFlag(indicator, "data-animate", animate && indicator.hasAttribute("data-visible"));
437
+ setFlag(indicator, "data-animate", animate && visible);
437
438
  style.left = left;
438
439
  style.top = top;
439
440
  style.width = width;
440
441
  style.height = height;
441
442
  }
443
+ if (!visible) setFlag(indicator, "data-fade", animate);
444
+ else if (!animate) setFlag(indicator, "data-fade", false);
442
445
  setFlag(indicator, "data-visible", true);
443
446
  }
444
447
  function endIndicatorGlide(event) {
@@ -446,6 +449,7 @@ function endIndicatorGlide(event) {
446
449
  if (["left", "top", "width", "height"].includes(event.propertyName)) {
447
450
  setFlag(event.currentTarget, "data-animate", false);
448
451
  }
452
+ if (event.propertyName === "opacity") setFlag(event.currentTarget, "data-fade", false);
449
453
  }
450
454
  function offsetIn(scroller, item) {
451
455
  let offset = 0;
@@ -1833,7 +1837,14 @@ function DialogActions({ className, children, ...rest }) {
1833
1837
  }
1834
1838
  DialogActions.displayName = "Dialog.Actions";
1835
1839
  function DialogBody({ className, ...rest }) {
1836
- return /* @__PURE__ */ jsx9(ScrollContainer, { className: cx(DialogParts_default.body, className), ...rest });
1840
+ return /* @__PURE__ */ jsx9(
1841
+ ScrollContainer,
1842
+ {
1843
+ overscrollBehavior: "contain",
1844
+ className: cx(DialogParts_default.body, className),
1845
+ ...rest
1846
+ }
1847
+ );
1837
1848
  }
1838
1849
  DialogBody.displayName = "Dialog.Body";
1839
1850
  function flowOf(parent) {
@@ -13434,9 +13445,24 @@ function estimateOf(body, specs, shell, reactions, author, actionRows) {
13434
13445
  return Math.round(size + (reactions ? 36 : 0) + actionRows * ACTIONS_ESTIMATE + 8);
13435
13446
  }
13436
13447
  var NO_REACTIONS = [];
13437
- function isLinkKey(props) {
13448
+ var ABSOLUTE_ADDRESS = /^([a-z][a-z\d+.-]*:|\/\/)/i;
13449
+ function leavesProduct(address) {
13450
+ if (typeof location === "undefined") return ABSOLUTE_ADDRESS.test(address);
13451
+ try {
13452
+ return new URL(address, location.href).origin !== location.origin;
13453
+ } catch {
13454
+ return ABSOLUTE_ADDRESS.test(address);
13455
+ }
13456
+ }
13457
+ function linkMarkOf(props) {
13438
13458
  const child = props.children;
13439
- return props.asChild === true && React43.isValidElement(child) && child.type === "a" && child.props.href !== void 0;
13459
+ if (props.asChild !== true || !React43.isValidElement(child)) {
13460
+ return void 0;
13461
+ }
13462
+ const { href, to } = child.props;
13463
+ const address = typeof href === "string" ? href : typeof to === "string" ? to : void 0;
13464
+ if (address === void 0) return void 0;
13465
+ return leavesProduct(address) ? "action.externalLink" : "action.openApp";
13440
13466
  }
13441
13467
  function MessageActions({ className, children, ...rest }) {
13442
13468
  const { pending, track: track2 } = usePendingKeys();
@@ -13445,10 +13471,12 @@ function MessageActions({ className, children, ...rest }) {
13445
13471
  return child;
13446
13472
  }
13447
13473
  const { props } = child;
13448
- const link = isLinkKey(props) ? React43.cloneElement(props.children, {
13474
+ const mark2 = linkMarkOf(props);
13475
+ const linkChild = props.children;
13476
+ const link = mark2 ? React43.cloneElement(linkChild, {
13449
13477
  children: /* @__PURE__ */ jsxs32(Fragment22, { children: [
13450
- props.children.props.children,
13451
- /* @__PURE__ */ jsx43(Icon, { name: "action.externalLink", size: "xs", className: Message_default.linkMark })
13478
+ linkChild.props.children,
13479
+ /* @__PURE__ */ jsx43(Icon, { name: mark2, size: "xs", className: Message_default.linkMark })
13452
13480
  ] })
13453
13481
  }) : void 0;
13454
13482
  return React43.cloneElement(child, {
@@ -19812,6 +19840,7 @@ function CommandMenuList({ className, children, ref, ...rest }) {
19812
19840
  {
19813
19841
  ...rest,
19814
19842
  ref: mergedRef,
19843
+ overscrollBehavior: "contain",
19815
19844
  id: listboxId,
19816
19845
  role: "listbox",
19817
19846
  "aria-busy": loading || loadingMore || void 0,
@@ -25470,7 +25499,6 @@ function DataTable({
25470
25499
  ref: scrollRef,
25471
25500
  axis: "both",
25472
25501
  edges: "none",
25473
- overscrollBehavior: "none",
25474
25502
  className: cx(fieldTierClass, DataTable_default.viewport),
25475
25503
  "data-size": "xs",
25476
25504
  style: { maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight },
@@ -28847,7 +28875,6 @@ function Gantt({
28847
28875
  ref: scrollRef,
28848
28876
  axis: "both",
28849
28877
  edges: "none",
28850
- overscrollBehavior: "none",
28851
28878
  className: Gantt_default.viewport,
28852
28879
  style: typeof scrollHeight === "number" ? { maxHeight: `${scrollHeight}px` } : void 0,
28853
28880
  onScroll: () => {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  defineGlyph
5
- } from "./chunk-QFHE5GKW.js";
5
+ } from "./chunk-T7IEJSTH.js";
6
6
 
7
7
  // src/icons/glyphs/a-arrow-down.tsx
8
8
  import { jsx, jsxs } from "react/jsx-runtime";