@stll/ui 0.5.2 → 0.7.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.
Files changed (39) hide show
  1. package/README.md +71 -2
  2. package/dist/components/application-shell.d.ts +27 -0
  3. package/dist/components/application-shell.js +25 -0
  4. package/dist/components/button-variants.d.ts +2 -2
  5. package/dist/components/input-group.d.ts +1 -1
  6. package/dist/components/loader.d.ts +36 -0
  7. package/dist/components/loader.js +54 -0
  8. package/dist/index.d.ts +12 -1
  9. package/dist/index.js +12 -1
  10. package/dist/inspector/chrome.d.ts +6 -1
  11. package/dist/inspector/chrome.js +8 -3
  12. package/dist/inspector/layout-tokens.d.ts +1 -2
  13. package/dist/inspector/layout-tokens.js +1 -2
  14. package/dist/kanban/index.d.ts +3 -1
  15. package/dist/kanban/index.js +3 -1
  16. package/dist/kanban/sortable-edge.d.ts +39 -0
  17. package/dist/kanban/sortable-edge.js +27 -0
  18. package/dist/kanban/sortable-interactions.d.ts +75 -0
  19. package/dist/kanban/sortable-interactions.js +210 -0
  20. package/dist/kanban/touch-identity.d.ts +8 -0
  21. package/dist/kanban/touch-identity.js +4 -0
  22. package/dist/lib/initials.d.ts +16 -0
  23. package/dist/lib/initials.js +27 -0
  24. package/dist/review/review-author-avatar.d.ts +23 -0
  25. package/dist/review/review-author-avatar.js +30 -0
  26. package/dist/review/review-comment-card.d.ts +33 -0
  27. package/dist/review/review-comment-card.js +76 -0
  28. package/dist/review/review-decision-actions.d.ts +32 -0
  29. package/dist/review/review-decision-actions.js +74 -0
  30. package/dist/review/review-diff-text.d.ts +33 -0
  31. package/dist/review/review-diff-text.js +67 -0
  32. package/dist/review/review-out-of-date-notice.d.ts +28 -0
  33. package/dist/review/review-out-of-date-notice.js +32 -0
  34. package/dist/review/review-severity-dot.d.ts +27 -0
  35. package/dist/review/review-severity-dot.js +35 -0
  36. package/dist/review/review-status-badge.d.ts +30 -0
  37. package/dist/review/review-status-badge.js +45 -0
  38. package/dist/styles/theme.css +26 -0
  39. package/package.json +58 -5
@@ -0,0 +1,67 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/review/review-diff-text.tsx
4
+ const TRACKED_DELETION_STYLE = {
5
+ color: "color-mix(in oklch, var(--destructive) 35%, var(--muted-foreground))",
6
+ textDecorationLine: "line-through",
7
+ textDecorationThickness: "1px",
8
+ textDecorationColor: "color-mix(in oklch, var(--destructive) 30%, var(--muted-foreground))"
9
+ };
10
+ const TRACKED_INSERTION_STYLE = {
11
+ borderRadius: "3px",
12
+ padding: "0 2px",
13
+ backgroundColor: "color-mix(in oklch, var(--success) 14%, transparent)",
14
+ boxShadow: "inset 0 0 0 1px color-mix(in oklch, var(--success) 28%, transparent)",
15
+ textDecorationLine: "none",
16
+ boxDecorationBreak: "clone",
17
+ WebkitBoxDecorationBreak: "clone"
18
+ };
19
+ /** Inserted text, wherever it is shown. */
20
+ const ReviewDiffInsertion = ({ className, children }) => /* @__PURE__ */ jsx("ins", {
21
+ className,
22
+ style: TRACKED_INSERTION_STYLE,
23
+ children
24
+ });
25
+ /** Deleted text, wherever it is shown. */
26
+ const ReviewDiffDeletion = ({ className, children }) => /* @__PURE__ */ jsx("del", {
27
+ className,
28
+ style: TRACKED_DELETION_STYLE,
29
+ children
30
+ });
31
+ /** A word-level diff rendered inline, in the product's one track-changes
32
+ * language. */
33
+ const ReviewDiffText = ({ segments, className }) => {
34
+ const keys = reviewDiffSegmentKeys(segments);
35
+ return /* @__PURE__ */ jsx("span", {
36
+ className: cn(className),
37
+ "data-slot": "review-diff-text",
38
+ children: segments.map((segment, index) => /* @__PURE__ */ jsx(ReviewDiffSegmentSpan, { segment }, keys[index]))
39
+ });
40
+ };
41
+ /**
42
+ * A stable render key per segment. Type and text alone repeat inside a single
43
+ * diff (the same word deleted twice), so each repetition carries its
44
+ * occurrence count; the result is stable across renders of the same diff and
45
+ * never falls back to the array index.
46
+ */
47
+ const reviewDiffSegmentKeys = (segments) => {
48
+ const seen = /* @__PURE__ */ new Map();
49
+ return segments.map((segment) => {
50
+ const base = `${segment.type}-${segment.text}`;
51
+ const occurrence = seen.get(base) ?? 0;
52
+ seen.set(base, occurrence + 1);
53
+ return `${base}-${occurrence}`;
54
+ });
55
+ };
56
+ const ReviewDiffSegmentSpan = ({ segment }) => {
57
+ switch (segment.type) {
58
+ case "insert": return /* @__PURE__ */ jsx(ReviewDiffInsertion, { children: segment.text });
59
+ case "delete": return /* @__PURE__ */ jsx(ReviewDiffDeletion, { children: segment.text });
60
+ case "equal": return /* @__PURE__ */ jsx("span", { children: segment.text });
61
+ default:
62
+ segment.type;
63
+ return null;
64
+ }
65
+ };
66
+ //#endregion
67
+ export { ReviewDiffDeletion, ReviewDiffInsertion, ReviewDiffText, TRACKED_DELETION_STYLE, TRACKED_INSERTION_STYLE, reviewDiffSegmentKeys };
@@ -0,0 +1,28 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/review/review-out-of-date-notice.d.ts
3
+ type ReviewOutOfDateTone = "warning" | "muted";
4
+ /**
5
+ * One reason a review has fallen behind. Carries its own key so the list is
6
+ * never rendered by array index: reasons come and go independently (the
7
+ * document changed, the playbook moved on, the source was deleted) and each
8
+ * one has a stable identity at its call site.
9
+ */
10
+ type ReviewOutOfDateReason = {
11
+ id: string;
12
+ label: ReactNode;
13
+ };
14
+ type ReviewOutOfDateNoticeProps = {
15
+ reasons: readonly ReviewOutOfDateReason[];
16
+ actionLabel?: ReactNode;
17
+ onAction?: (() => void) | undefined;
18
+ tone?: ReviewOutOfDateTone;
19
+ className?: string;
20
+ };
21
+ /**
22
+ * What a review no longer reflects. Every applicable reason is listed
23
+ * together: they are different reasons to run again, and a reviewer working
24
+ * through findings should see each one rather than the first.
25
+ */
26
+ declare const ReviewOutOfDateNotice: ({ reasons, actionLabel, onAction, tone, className }: ReviewOutOfDateNoticeProps) => import("react").JSX.Element | null;
27
+ //#endregion
28
+ export { ReviewOutOfDateNotice, ReviewOutOfDateReason, ReviewOutOfDateTone };
@@ -0,0 +1,32 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { Button } from "../components/button.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/review/review-out-of-date-notice.tsx
5
+ /**
6
+ * What a review no longer reflects. Every applicable reason is listed
7
+ * together: they are different reasons to run again, and a reviewer working
8
+ * through findings should see each one rather than the first.
9
+ */
10
+ const ReviewOutOfDateNotice = ({ reasons, actionLabel, onAction, tone = "warning", className }) => {
11
+ if (reasons.length === 0) return null;
12
+ return /* @__PURE__ */ jsxs("div", {
13
+ className: cn("mb-2 rounded-lg border px-3 py-2", TONE_CLASS[tone], className),
14
+ "data-slot": "review-out-of-date-notice",
15
+ children: [/* @__PURE__ */ jsx("ul", {
16
+ className: "space-y-1 text-xs",
17
+ children: reasons.map((reason) => /* @__PURE__ */ jsx("li", { children: reason.label }, reason.id))
18
+ }), onAction === void 0 ? null : /* @__PURE__ */ jsx(Button, {
19
+ className: "mt-2",
20
+ onClick: onAction,
21
+ size: "xs",
22
+ variant: "outline",
23
+ children: actionLabel
24
+ })]
25
+ });
26
+ };
27
+ const TONE_CLASS = {
28
+ warning: "border-warning/30 bg-warning/10 text-warning-foreground",
29
+ muted: "border-border bg-muted/50 text-muted-foreground"
30
+ };
31
+ //#endregion
32
+ export { ReviewOutOfDateNotice };
@@ -0,0 +1,27 @@
1
+ import { ReviewStatusTone } from "./review-status-badge.js";
2
+ //#region src/review/review-severity-dot.d.ts
3
+ /**
4
+ * How bad a finding is, on the one scale every review surface reports against.
5
+ * Vocabularies that stop short of five levels (a playbook's blocker/high/
6
+ * medium/low, a suggestion's high/medium/low/unspecified) map onto this at
7
+ * their call site rather than growing a palette of their own.
8
+ */
9
+ type ReviewSeverityLevel = "critical" | "high" | "medium" | "low" | "none";
10
+ type ReviewSeverityDotProps = {
11
+ level: ReviewSeverityLevel;
12
+ className?: string | undefined;
13
+ };
14
+ /** The dot that precedes a severity label, and the one place a severity level
15
+ * turns into a colour. */
16
+ declare const ReviewSeverityDot: ({ level, className }: ReviewSeverityDotProps) => import("react").JSX.Element;
17
+ type ReviewStatusDotProps = {
18
+ tone: ReviewStatusTone;
19
+ className?: string | undefined;
20
+ };
21
+ /** The same dot keyed by tone, for vocabularies that are not severities
22
+ * (verdicts, directed impact, comparison assessments). */
23
+ declare const ReviewStatusDot: ({ tone, className }: ReviewStatusDotProps) => import("react").JSX.Element;
24
+ /** The tone a severity level carries, so a badge and its dot cannot disagree. */
25
+ declare const reviewSeverityTone: (level: ReviewSeverityLevel) => ReviewStatusTone;
26
+ //#endregion
27
+ export { ReviewSeverityDot, ReviewSeverityLevel, ReviewStatusDot, reviewSeverityTone };
@@ -0,0 +1,35 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ //#region src/review/review-severity-dot.tsx
4
+ /** The dot that precedes a severity label, and the one place a severity level
5
+ * turns into a colour. */
6
+ const ReviewSeverityDot = ({ level, className }) => /* @__PURE__ */ jsx(ReviewStatusDot, {
7
+ className,
8
+ tone: SEVERITY_TONE[level]
9
+ });
10
+ /** The same dot keyed by tone, for vocabularies that are not severities
11
+ * (verdicts, directed impact, comparison assessments). */
12
+ const ReviewStatusDot = ({ tone, className }) => /* @__PURE__ */ jsx("span", {
13
+ "aria-hidden": "true",
14
+ className: cn(REVIEW_STATUS_DOT_BASE_CLASS, TONE_DOT_CLASS[tone], className),
15
+ "data-slot": "review-status-dot"
16
+ });
17
+ /** The tone a severity level carries, so a badge and its dot cannot disagree. */
18
+ const reviewSeverityTone = (level) => SEVERITY_TONE[level];
19
+ const REVIEW_STATUS_DOT_BASE_CLASS = "size-1.5 shrink-0 rounded-full";
20
+ const SEVERITY_TONE = {
21
+ critical: "destructive",
22
+ high: "destructive",
23
+ medium: "warning",
24
+ low: "neutral",
25
+ none: "success"
26
+ };
27
+ const TONE_DOT_CLASS = {
28
+ neutral: "bg-muted-foreground",
29
+ success: "bg-success",
30
+ warning: "bg-warning",
31
+ destructive: "bg-destructive",
32
+ highlight: "bg-highlight-foreground"
33
+ };
34
+ //#endregion
35
+ export { ReviewSeverityDot, ReviewStatusDot, reviewSeverityTone };
@@ -0,0 +1,30 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/review/review-status-badge.d.ts
3
+ /**
4
+ * The semantic weight of a review status, independent of the words a surface
5
+ * uses for it. Playbook verdicts, overall risk, proposal states, suggestion
6
+ * decisions and approval states each map their own vocabulary onto one tone,
7
+ * so "this is fine" reads as the same green everywhere and a reviewer never
8
+ * has to relearn a palette when moving between panels.
9
+ */
10
+ type ReviewStatusTone = "neutral" | "success" | "warning" | "destructive" | "highlight";
11
+ type ReviewStatusVariant = "solid" | "outline" | "strong";
12
+ type ReviewStatusSize = "xs" | "sm";
13
+ type ReviewStatusBadgeProps = {
14
+ tone: ReviewStatusTone;
15
+ /** Outlined by default. `solid` adds a tonal wash for a status that has to
16
+ * carry more weight than its neighbours (an overall risk, an approval);
17
+ * `strong` fills it outright, reserved for the one state on a surface that
18
+ * must escalate past every other badge beside it. */
19
+ variant?: ReviewStatusVariant;
20
+ size?: ReviewStatusSize;
21
+ /** Leading glyph, typically a `<ReviewSeverityDot />`. */
22
+ icon?: ReactNode;
23
+ className?: string;
24
+ children: ReactNode;
25
+ };
26
+ /** One status pill for every review surface: one radius, one padding scale,
27
+ * one tone vocabulary. */
28
+ declare const ReviewStatusBadge: ({ tone, variant, size, icon, className, children }: ReviewStatusBadgeProps) => import("react").JSX.Element;
29
+ //#endregion
30
+ export { ReviewStatusBadge, ReviewStatusSize, ReviewStatusTone, ReviewStatusVariant };
@@ -0,0 +1,45 @@
1
+ import { cn } from "../lib/utils.js";
2
+ import { jsxs } from "react/jsx-runtime";
3
+ //#region src/review/review-status-badge.tsx
4
+ /** One status pill for every review surface: one radius, one padding scale,
5
+ * one tone vocabulary. */
6
+ const ReviewStatusBadge = ({ tone, variant = "outline", size = "xs", icon, className, children }) => /* @__PURE__ */ jsxs("span", {
7
+ className: cn(REVIEW_STATUS_BADGE_BASE_CLASS, SIZE_CLASS[size], VARIANT_CLASS[variant], TONE_CLASS[variant][tone], className),
8
+ "data-slot": "review-status-badge",
9
+ children: [icon, children]
10
+ });
11
+ const REVIEW_STATUS_BADGE_BASE_CLASS = "inline-flex shrink-0 items-center rounded-full border font-medium whitespace-nowrap";
12
+ const SIZE_CLASS = {
13
+ xs: "gap-1 px-1.5 py-0.5 text-[11px]",
14
+ sm: "gap-1.5 px-2 py-0.5 text-xs"
15
+ };
16
+ const TONE_CLASS = {
17
+ outline: {
18
+ neutral: "border-border text-muted-foreground",
19
+ success: "border-success/30 text-success",
20
+ warning: "border-warning/30 text-warning-foreground",
21
+ destructive: "border-destructive/30 text-destructive",
22
+ highlight: "border-highlight text-highlight-foreground"
23
+ },
24
+ solid: {
25
+ neutral: "border-transparent bg-muted text-muted-foreground",
26
+ success: "border-transparent bg-success/12 text-success",
27
+ warning: "border-transparent bg-warning/12 text-warning-foreground",
28
+ destructive: "border-transparent bg-destructive/12 text-destructive",
29
+ highlight: "border-transparent bg-highlight/50 text-highlight-foreground"
30
+ },
31
+ strong: {
32
+ neutral: "border-transparent bg-muted-foreground text-background",
33
+ success: "border-transparent bg-success text-success-foreground",
34
+ warning: "border-transparent bg-warning text-warning-foreground",
35
+ destructive: "border-transparent bg-destructive text-destructive-foreground",
36
+ highlight: "border-transparent bg-highlight text-highlight-foreground"
37
+ }
38
+ };
39
+ const VARIANT_CLASS = {
40
+ outline: "",
41
+ solid: "",
42
+ strong: "[&_[data-slot=review-status-dot]]:bg-current"
43
+ };
44
+ //#endregion
45
+ export { ReviewStatusBadge };
@@ -69,6 +69,32 @@
69
69
  affordance the user has to notice, not merely acknowledge. */
70
70
  --animate-attention-flash: attention-flash 700ms ease-out;
71
71
  --animate-attention-flash-twice: attention-flash 700ms ease-out 2;
72
+ /* The Stella mark breathing: the one indeterminate loading motion.
73
+ Opacity and scale only, so it never triggers layout. */
74
+ --animate-loader: loader 1.8s ease-in-out infinite;
75
+ /* A list item settling into place; callers stagger it by index. */
76
+ --animate-rise: rise 240ms ease-out both;
77
+ @keyframes loader {
78
+ 0%,
79
+ 100% {
80
+ opacity: 0.35;
81
+ transform: scale(0.94);
82
+ }
83
+ 50% {
84
+ opacity: 1;
85
+ transform: scale(1);
86
+ }
87
+ }
88
+ @keyframes rise {
89
+ from {
90
+ opacity: 0;
91
+ transform: translateY(4px);
92
+ }
93
+ to {
94
+ opacity: 1;
95
+ transform: translateY(0);
96
+ }
97
+ }
72
98
  @keyframes skeleton {
73
99
  to {
74
100
  background-position: -200% 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stll/ui",
3
- "version": "0.5.2",
3
+ "version": "0.7.0",
4
4
  "description": "Stella's design system: bidi-aware React primitives built on Base UI, the dockable inspector pane, and the Tailwind v4 theme they are styled with.",
5
5
  "keywords": [
6
6
  "base-ui",
@@ -41,6 +41,10 @@
41
41
  "types": "./dist/components/alert-dialog.d.ts",
42
42
  "import": "./dist/components/alert-dialog.js"
43
43
  },
44
+ "./application-shell": {
45
+ "types": "./dist/components/application-shell.d.ts",
46
+ "import": "./dist/components/application-shell.js"
47
+ },
44
48
  "./avatar": {
45
49
  "types": "./dist/components/avatar.d.ts",
46
50
  "import": "./dist/components/avatar.js"
@@ -133,6 +137,10 @@
133
137
  "types": "./dist/components/input-group.d.ts",
134
138
  "import": "./dist/components/input-group.js"
135
139
  },
140
+ "./initials": {
141
+ "types": "./dist/lib/initials.d.ts",
142
+ "import": "./dist/lib/initials.js"
143
+ },
136
144
  "./input-otp": {
137
145
  "types": "./dist/components/input-otp.d.ts",
138
146
  "import": "./dist/components/input-otp.js"
@@ -173,6 +181,34 @@
173
181
  "types": "./dist/components/preview-pane.d.ts",
174
182
  "import": "./dist/components/preview-pane.js"
175
183
  },
184
+ "./review-author-avatar": {
185
+ "types": "./dist/review/review-author-avatar.d.ts",
186
+ "import": "./dist/review/review-author-avatar.js"
187
+ },
188
+ "./review-comment-card": {
189
+ "types": "./dist/review/review-comment-card.d.ts",
190
+ "import": "./dist/review/review-comment-card.js"
191
+ },
192
+ "./review-decision-actions": {
193
+ "types": "./dist/review/review-decision-actions.d.ts",
194
+ "import": "./dist/review/review-decision-actions.js"
195
+ },
196
+ "./review-diff-text": {
197
+ "types": "./dist/review/review-diff-text.d.ts",
198
+ "import": "./dist/review/review-diff-text.js"
199
+ },
200
+ "./review-out-of-date-notice": {
201
+ "types": "./dist/review/review-out-of-date-notice.d.ts",
202
+ "import": "./dist/review/review-out-of-date-notice.js"
203
+ },
204
+ "./review-severity-dot": {
205
+ "types": "./dist/review/review-severity-dot.d.ts",
206
+ "import": "./dist/review/review-severity-dot.js"
207
+ },
208
+ "./review-status-badge": {
209
+ "types": "./dist/review/review-status-badge.d.ts",
210
+ "import": "./dist/review/review-status-badge.js"
211
+ },
176
212
  "./scroll-area": {
177
213
  "types": "./dist/components/scroll-area.d.ts",
178
214
  "import": "./dist/components/scroll-area.js"
@@ -201,6 +237,10 @@
201
237
  "types": "./dist/components/sheet.d.ts",
202
238
  "import": "./dist/components/sheet.js"
203
239
  },
240
+ "./loader": {
241
+ "types": "./dist/components/loader.d.ts",
242
+ "import": "./dist/components/loader.js"
243
+ },
204
244
  "./skeleton": {
205
245
  "types": "./dist/components/skeleton.d.ts",
206
246
  "import": "./dist/components/skeleton.js"
@@ -278,6 +318,10 @@
278
318
  "types": "./dist/components/alert-dialog.d.ts",
279
319
  "import": "./dist/components/alert-dialog.js"
280
320
  },
321
+ "./components/application-shell": {
322
+ "types": "./dist/components/application-shell.d.ts",
323
+ "import": "./dist/components/application-shell.js"
324
+ },
281
325
  "./components/avatar": {
282
326
  "types": "./dist/components/avatar.d.ts",
283
327
  "import": "./dist/components/avatar.js"
@@ -490,7 +534,10 @@
490
534
  "clean": "git clean -xdf dist .cache .turbo node_modules",
491
535
  "build": "tsdown",
492
536
  "pack:dry-run": "bun pm pack --dry-run",
493
- "test": "bun test src",
537
+ "test": "bun run test:unit",
538
+ "test:unit": "bun test src --path-ignore-patterns '**/*.playwright.spec.ts'",
539
+ "test:browser": "playwright test --config playwright.config.ts",
540
+ "pack:check": "cd ../.. && bun scripts/check-published-exports.ts packages/ui",
494
541
  "typecheck": "bun ../../packages/scripts/src/tsc-native.ts --noEmit",
495
542
  "lint": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --report-unused-disable-directives-severity=error --deny-warnings --type-aware packages/ui",
496
543
  "lint:fix": "cd ../.. && bun --bun oxlint -c oxlint.config.ts --type-aware --fix packages/ui",
@@ -506,8 +553,11 @@
506
553
  },
507
554
  "devDependencies": {
508
555
  "@atlaskit/pragmatic-drag-and-drop": "^3.0.0",
509
- "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.0.1",
556
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.1.0",
510
557
  "@base-ui/react": "1.7.0",
558
+ "@dnd-kit/core": "^6.3.1",
559
+ "@dnd-kit/sortable": "^10.0.0",
560
+ "@playwright/test": "^1.62.0",
511
561
  "@stll/typescript-config": "0.0.0",
512
562
  "@types/react": "^19.2.17",
513
563
  "@types/react-dom": "^19.2.3",
@@ -515,12 +565,15 @@
515
565
  "react": "^19.2.8",
516
566
  "react-dom": "^19.2.8",
517
567
  "tailwindcss": "4.3.3",
518
- "tsdown": "0.22.14"
568
+ "tsdown": "0.22.14",
569
+ "vite": "8.2.1"
519
570
  },
520
571
  "peerDependencies": {
521
572
  "@atlaskit/pragmatic-drag-and-drop": "^3.0.0",
522
- "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.0.1",
573
+ "@atlaskit/pragmatic-drag-and-drop-auto-scroll": "^3.1.0",
523
574
  "@base-ui/react": "^1.7.0",
575
+ "@dnd-kit/core": "^6.3.1",
576
+ "@dnd-kit/sortable": "^10.0.0",
524
577
  "react": ">=19",
525
578
  "react-dom": ">=19",
526
579
  "tailwindcss": "^4.3.0"