@nadicodeai/ui 12.1.27 → 12.1.28

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.
@@ -0,0 +1 @@
1
+ clean
@@ -46,7 +46,7 @@ function DrawerContent({ className, children, ...props }) {
46
46
  // Stack.
47
47
  "[--bleed:3rem] [--peek:1rem] [--stack-height:var(--drawer-frontmost-height,var(--drawer-height,0px))] [--stack-peek-offset:max(0px,calc((var(--nested-drawers)-var(--stack-progress))*var(--peek)))] [--stack-progress:clamp(0,var(--drawer-swipe-progress),1)] [--stack-scale-base:max(0,calc(1-(var(--nested-drawers)*var(--stack-step))))] [--stack-scale:clamp(0,calc(var(--stack-scale-base)+(var(--stack-step)*var(--stack-progress))),1)] [--stack-shrink:calc(1-var(--stack-scale))] [--stack-step:0.05]",
48
48
  // Transitions.
49
- "data-ending-style:transform-(--closed-transform) data-ending-style:opacity-[0.9999] data-ending-style:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] data-nested-drawer-swiping:duration-0 data-ending-style:data-nested-drawer-swiping:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] data-starting-style:transform-(--closed-transform) data-swiping:duration-0 data-ending-style:data-swiping:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] motion-reduce:data-ending-style:transform-none motion-reduce:data-starting-style:transform-none",
49
+ "data-ending-style:transform-(--closed-transform) data-ending-style:opacity-[0.9999] data-ending-style:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] data-nested-drawer-swiping:duration-0 data-ending-style:data-nested-drawer-swiping:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] data-starting-style:transform-(--closed-transform) data-swiping:duration-0 data-ending-style:data-swiping:duration-[calc(var(--drawer-swipe-strength)*var(--nc-duration-drawer-swipe))] motion-reduce:data-ending-style:transform-none motion-reduce:data-starting-style:transform-none motion-reduce:data-ending-style:opacity-0 motion-reduce:data-starting-style:opacity-0",
50
50
  // Axis: y.
51
51
  "data-[swipe-axis=y]:inset-x-0 data-[swipe-axis=y]:data-nested-drawer-open:h-(--stack-height)",
52
52
  // Axis: x.
@@ -20,6 +20,7 @@ import { noPairedSizeUtility } from "./rules/no-paired-size-utility.js";
20
20
  import { noRestingSettingsControl } from "./rules/no-resting-settings-control.js";
21
21
  import { oneControlHeight } from "./rules/one-control-height.js";
22
22
  import { overlayBodyOwnsScroll } from "./rules/overlay-body-owns-scroll.js";
23
+ import { overlayMountsClosed } from "./rules/overlay-mounts-closed.js";
23
24
  import { tableColumnWrapsByMeta } from "./rules/table-column-wraps-by-meta.js";
24
25
  import { noShadcnAppearanceOverride } from "./rules/no-shadcn-appearance-override.js";
25
26
  import { noSubjectDerivedExpectation } from "./rules/no-subject-derived-expectation.js";
@@ -98,6 +99,7 @@ export const strictDesignSystemRules = {
98
99
  "nadicodeai/no-shadcn-appearance-override": "error",
99
100
  "nadicodeai/no-token-category-bypass": "error",
100
101
  "nadicodeai/overlay-body-owns-scroll": "error",
102
+ "nadicodeai/overlay-mounts-closed": "error",
101
103
  "nadicodeai/prefer-radio-for-few-static-options": "error",
102
104
  };
103
105
 
@@ -135,6 +137,7 @@ const plugin = {
135
137
  "no-token-category-bypass": noTokenCategoryBypass,
136
138
  "one-control-height": oneControlHeight,
137
139
  "overlay-body-owns-scroll": overlayBodyOwnsScroll,
140
+ "overlay-mounts-closed": overlayMountsClosed,
138
141
  "table-column-wraps-by-meta": tableColumnWrapsByMeta,
139
142
  "server-action-discipline": serverActionDiscipline,
140
143
  "settings-section-description": settingsSectionDescription,
@@ -0,0 +1,102 @@
1
+ /*
2
+ * An overlay is mounted closed and then opened, so its entry runs.
3
+ *
4
+ * A dialog, drawer, sheet or menu fades in from its starting style when its
5
+ * `open` turns true on a mounted element. One that first mounts already open
6
+ * has no earlier frame to transition from, so it appears at full opacity, and
7
+ * one that unmounts on dismissal never plays its exit. Three spellings mount an
8
+ * overlay open: an `open` fixed to true (its parent mounts it on demand), a
9
+ * truthy `defaultOpen`, and a `key` that changes per opening, which remounts it
10
+ * in the same render that opens it. A list key inside a `.map` callback and a
11
+ * literal key are an element's identity, not an opening.
12
+ *
13
+ * Standard tool checked first: `no-restricted-syntax` can match the attribute,
14
+ * but not the renamed import or the enclosing `.map` a list key sits in, so the
15
+ * shared component-name reader resolves it here.
16
+ */
17
+ import { jsxComponentName } from "./jsx-class-utility.js";
18
+
19
+ const OVERLAY = /Dialog|Drawer|Sheet|Popover|Menu|Tooltip|HoverCard|Combobox/;
20
+ const PART =
21
+ /(Content|Trigger|Title|Description|Header|Footer|Body|Item|Group|Label|Separator|Close|Portal|Overlay|Backdrop)$/;
22
+ const LIST_CALLBACK = new Set(["map", "flatMap"]);
23
+
24
+ function attribute(node, name) {
25
+ return node.attributes.find(
26
+ (entry) =>
27
+ entry.type === "JSXAttribute" &&
28
+ entry.name.type === "JSXIdentifier" &&
29
+ entry.name.name === name,
30
+ );
31
+ }
32
+
33
+ function isTrue(entry) {
34
+ if (!entry) return false;
35
+ if (entry.value === null) return true;
36
+ return (
37
+ entry.value.type === "JSXExpressionContainer" &&
38
+ entry.value.expression.type === "Literal" &&
39
+ entry.value.expression.value === true
40
+ );
41
+ }
42
+
43
+ function isLiteralKey(entry) {
44
+ if (entry.value?.type === "Literal") return true;
45
+ const expression =
46
+ entry.value?.type === "JSXExpressionContainer" ? entry.value.expression : undefined;
47
+ return (
48
+ expression?.type === "Literal" ||
49
+ (expression?.type === "TemplateLiteral" && expression.expressions.length === 0)
50
+ );
51
+ }
52
+
53
+ function insideListCallback(node, context) {
54
+ return context.sourceCode
55
+ .getAncestors(node)
56
+ .some(
57
+ (ancestor) =>
58
+ (ancestor.type === "ArrowFunctionExpression" || ancestor.type === "FunctionExpression") &&
59
+ ancestor.parent?.type === "CallExpression" &&
60
+ ancestor.parent.arguments.includes(ancestor) &&
61
+ ancestor.parent.callee.type === "MemberExpression" &&
62
+ LIST_CALLBACK.has(ancestor.parent.callee.property.name),
63
+ );
64
+ }
65
+
66
+ export const overlayMountsClosed = {
67
+ meta: {
68
+ type: "problem",
69
+ docs: {
70
+ description:
71
+ "Disallow an overlay that mounts already open, so its entry and exit transitions run",
72
+ },
73
+ schema: [],
74
+ messages: {
75
+ openFixed:
76
+ "<{{name}}> is given `open` fixed to true, so it only exists while open and neither its fade in nor its fade out runs. Keep it mounted and drive `open` from state.",
77
+ defaultOpen:
78
+ "<{{name}}> mounts open through `defaultOpen`, so its entry never runs. Mount it closed and open it from state.",
79
+ keyPerOpening:
80
+ "<{{name}}> takes a `key` that remounts it, so an opening that changes the key mounts it already open and its fade in never runs. Keep one mounted overlay and reset its content another way, such as a key on the content inside it.",
81
+ },
82
+ },
83
+ create(context) {
84
+ return {
85
+ JSXOpeningElement(node) {
86
+ const name = jsxComponentName(node, context);
87
+ if (!name || !OVERLAY.test(name) || PART.test(name)) return;
88
+
89
+ if (isTrue(attribute(node, "open"))) {
90
+ context.report({ node, messageId: "openFixed", data: { name } });
91
+ }
92
+ if (isTrue(attribute(node, "defaultOpen"))) {
93
+ context.report({ node, messageId: "defaultOpen", data: { name } });
94
+ }
95
+ const key = attribute(node, "key");
96
+ if (key && !isLiteralKey(key) && !insideListCallback(node, context)) {
97
+ context.report({ node, messageId: "keyPerOpening", data: { name } });
98
+ }
99
+ },
100
+ };
101
+ },
102
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"tool-fallback.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-fallback.tsx"],"names":[],"mappings":"AAUA,OAAO,EAOL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAA0C,MAAM,0BAA0B,CAAC;AAQ/F,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GAAG;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAydF,QAAA,MAAM,YAAY,EAAwC,4BAA4B,CAAC;AAIvF,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"tool-fallback.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-fallback.tsx"],"names":[],"mappings":"AAUA,OAAO,EAOL,KAAK,4BAA4B,EAClC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAA0C,MAAM,0BAA0B,CAAC;AAO/F,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GAAG;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAydF,QAAA,MAAM,YAAY,EAAwC,4BAA4B,CAAC;AAIvF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -5,13 +5,13 @@ import { AlertCircleIcon, CheckIcon, ChevronDownIcon, CircleDotIcon, XCircleIcon
5
5
  import { useScrollLock, useToolCallElapsed, } from "@assistant-ui/react";
6
6
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
7
7
  import { cn } from "../../lib/utils.js";
8
+ import { disclosureDuration, disclosureDurationMs } from "../../lib/motion.js";
8
9
  import { Button } from "../../components/button.js";
9
- const ANIMATION_DURATION = 200;
10
10
  const pressable = "active:scale-[0.98]";
11
11
  function ToolFallbackRoot({ className, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, children, ...props }) {
12
12
  const collapsibleRef = useRef(null);
13
13
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
14
- const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
14
+ const lockScroll = useScrollLock(collapsibleRef, disclosureDurationMs);
15
15
  const isControlled = controlledOpen !== undefined;
16
16
  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
17
17
  const handleOpenChange = useCallback((open) => {
@@ -22,7 +22,7 @@ function ToolFallbackRoot({ className, open: controlledOpen, onOpenChange: contr
22
22
  controlledOnOpenChange?.(open);
23
23
  }, [lockScroll, isControlled, controlledOnOpenChange]);
24
24
  return (_jsx(Collapsible, { ref: collapsibleRef, "data-slot": "tool-fallback-root", open: isOpen, onOpenChange: handleOpenChange, className: cn("aui-tool-fallback-root group/tool-fallback-root w-full", className), style: {
25
- "--animation-duration": `${ANIMATION_DURATION}ms`,
25
+ "--animation-duration": disclosureDuration,
26
26
  }, ...props, children: children }));
27
27
  }
28
28
  const statusIconMap = {
@@ -1 +1 @@
1
- {"version":3,"file":"tool-group.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-group.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAK/F,QAAA,MAAM,iBAAiB;;8EASrB,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GACC,YAAY,CAAC,OAAO,iBAAiB,CAAC,GAAG;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEJ,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,OAAO,EACP,IAAI,EAAE,cAAc,EACpB,YAAY,EAAE,sBAAsB,EACpC,WAAmB,EACnB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,+BAqCpB;AAED,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,MAAc,EACd,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,GAAG;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BAwCA;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,+BAyBjD;AAED,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"tool-group.d.ts","sourceRoot":"","sources":["../../../src/internal/assistant-ui/tool-group.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAI/F,QAAA,MAAM,iBAAiB;;8EASrB,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CACnC,KAAK,CAAC,cAAc,CAAC,OAAO,WAAW,CAAC,EACxC,MAAM,GAAG,cAAc,CACxB,GACC,YAAY,CAAC,OAAO,iBAAiB,CAAC,GAAG;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEJ,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,OAAO,EACP,IAAI,EAAE,cAAc,EACpB,YAAY,EAAE,sBAAsB,EACpC,WAAmB,EACnB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,kBAAkB,+BAqCpB;AAED,iBAAS,gBAAgB,CAAC,EACxB,KAAK,EACL,MAAc,EACd,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,GAAG;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,+BAwCA;AAED,iBAAS,gBAAgB,CAAC,EACxB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,kBAAkB,CAAC,+BAyBjD;AAED,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,CAAC"}
@@ -6,7 +6,7 @@ import { cva } from "class-variance-authority";
6
6
  import { useScrollLock } from "@assistant-ui/react";
7
7
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "../../components/collapsible.js";
8
8
  import { cn } from "../../lib/utils.js";
9
- const ANIMATION_DURATION = 200;
9
+ import { disclosureDuration, disclosureDurationMs } from "../../lib/motion.js";
10
10
  const toolGroupVariants = cva("aui-tool-group-root group/tool-group w-full", {
11
11
  variants: {
12
12
  variant: {
@@ -20,7 +20,7 @@ const toolGroupVariants = cva("aui-tool-group-root group/tool-group w-full", {
20
20
  function ToolGroupRoot({ className, variant, open: controlledOpen, onOpenChange: controlledOnOpenChange, defaultOpen = false, children, ...props }) {
21
21
  const collapsibleRef = useRef(null);
22
22
  const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);
23
- const lockScroll = useScrollLock(collapsibleRef, ANIMATION_DURATION);
23
+ const lockScroll = useScrollLock(collapsibleRef, disclosureDurationMs);
24
24
  const isControlled = controlledOpen !== undefined;
25
25
  const isOpen = isControlled ? controlledOpen : uncontrolledOpen;
26
26
  const handleOpenChange = useCallback((open) => {
@@ -31,7 +31,7 @@ function ToolGroupRoot({ className, variant, open: controlledOpen, onOpenChange:
31
31
  controlledOnOpenChange?.(open);
32
32
  }, [lockScroll, isControlled, controlledOnOpenChange]);
33
33
  return (_jsx(Collapsible, { ref: collapsibleRef, "data-slot": "tool-group-root", "data-variant": variant ?? "outline", open: isOpen, onOpenChange: handleOpenChange, className: cn(toolGroupVariants({ variant }), "group/tool-group-root", className), style: {
34
- "--animation-duration": `${ANIMATION_DURATION}ms`,
34
+ "--animation-duration": disclosureDuration,
35
35
  }, ...props, children: children }));
36
36
  }
37
37
  function ToolGroupTrigger({ count, active = false, className, ...props }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadicodeai/ui",
3
- "version": "12.1.27",
3
+ "version": "12.1.28",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -76,7 +76,7 @@
76
76
  "@assistant-ui/react": "0.15.21",
77
77
  "@assistant-ui/react-markdown": "0.14.16",
78
78
  "@base-ui/react": "^1.8.0",
79
- "@nadicodeai/design-system": "12.1.27",
79
+ "@nadicodeai/design-system": "12.1.28",
80
80
  "class-variance-authority": "^0.7.1",
81
81
  "clsx": "^2.1.1",
82
82
  "cmdk": "^1.1.1",