@dust-tt/sparkle 0.2.275 → 0.2.276

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 (48) hide show
  1. package/dist/cjs/index.js +103 -25
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/esm/components/Dialog.js +1 -1
  4. package/dist/esm/components/Dialog.js.map +1 -1
  5. package/dist/esm/components/Input.d.ts.map +1 -1
  6. package/dist/esm/components/Input.js +20 -7
  7. package/dist/esm/components/Input.js.map +1 -1
  8. package/dist/esm/components/Label.js +1 -1
  9. package/dist/esm/components/Label.js.map +1 -1
  10. package/dist/esm/components/NavigationList.d.ts +18 -0
  11. package/dist/esm/components/NavigationList.d.ts.map +1 -0
  12. package/dist/esm/components/NavigationList.js +70 -0
  13. package/dist/esm/components/NavigationList.js.map +1 -0
  14. package/dist/esm/components/NewDropdown.js +2 -2
  15. package/dist/esm/components/NewDropdown.js.map +1 -1
  16. package/dist/esm/components/Popover.js +1 -1
  17. package/dist/esm/components/RadioGroup.d.ts.map +1 -1
  18. package/dist/esm/components/RadioGroup.js +4 -4
  19. package/dist/esm/components/RadioGroup.js.map +1 -1
  20. package/dist/esm/components/Spinner.js +1 -1
  21. package/dist/esm/components/Tree.d.ts +2 -1
  22. package/dist/esm/components/Tree.d.ts.map +1 -1
  23. package/dist/esm/components/Tree.js +8 -8
  24. package/dist/esm/components/Tree.js.map +1 -1
  25. package/dist/esm/components/index.d.ts +2 -1
  26. package/dist/esm/components/index.d.ts.map +1 -1
  27. package/dist/esm/components/index.js +2 -1
  28. package/dist/esm/components/index.js.map +1 -1
  29. package/dist/esm/stories/Input.stories.js +1 -1
  30. package/dist/esm/stories/Input.stories.js.map +1 -1
  31. package/dist/esm/stories/NavigationList.stories.d.ts +7 -0
  32. package/dist/esm/stories/NavigationList.stories.d.ts.map +1 -0
  33. package/dist/esm/stories/NavigationList.stories.js +140 -0
  34. package/dist/esm/stories/NavigationList.stories.js.map +1 -0
  35. package/dist/sparkle.css +95 -98
  36. package/package.json +1 -1
  37. package/src/components/Dialog.tsx +1 -1
  38. package/src/components/Input.tsx +44 -31
  39. package/src/components/Label.tsx +1 -1
  40. package/src/components/NavigationList.tsx +137 -0
  41. package/src/components/NewDropdown.tsx +2 -2
  42. package/src/components/Popover.tsx +1 -1
  43. package/src/components/RadioGroup.tsx +20 -22
  44. package/src/components/Spinner.tsx +1 -1
  45. package/src/components/Tree.tsx +10 -8
  46. package/src/components/index.ts +6 -1
  47. package/src/stories/Input.stories.tsx +14 -14
  48. package/src/stories/NavigationList.stories.tsx +173 -0
@@ -0,0 +1,137 @@
1
+ import { cva, type VariantProps } from "class-variance-authority";
2
+ import * as React from "react";
3
+
4
+ import { Button, Icon } from "@sparkle/components/";
5
+ import { MoreIcon } from "@sparkle/icons";
6
+ import { cn } from "@sparkle/lib/utils";
7
+
8
+ const listStyles = cva("s-flex", {
9
+ variants: {
10
+ layout: {
11
+ container: "s-gap-1 s-flex-col s-overflow-hidden",
12
+ item: cn(
13
+ "s-box-border s-items-center s-w-full s-flex s-gap-1.5 s-cursor-pointer s-select-none s-items-center s-outline-none s-rounded-xl s-text-sm s-px-3 s-py-2 s-transition-colors s-duration-300",
14
+ "data-[disabled]:s-pointer-events-none data-[disabled]:s-text-muted-foreground",
15
+ "hover:s-text-foreground hover:s-bg-structure-150"
16
+ ),
17
+ },
18
+ state: {
19
+ active: "active:s-bg-structure-200",
20
+ selected: "s-text-foreground s-font-medium s-bg-structure-150",
21
+ unselected: "s-text-muted-foreground",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ layout: "container",
26
+ state: "unselected",
27
+ },
28
+ });
29
+
30
+ const labelStyles = cva(
31
+ "s-font-semibold s-pt-6 s-pb-2 s-text-xs s-whitespace-nowrap s-overflow-hidden s-text-ellipsis"
32
+ );
33
+
34
+ const NavigationList = React.forwardRef<
35
+ HTMLDivElement,
36
+ React.HTMLAttributes<HTMLDivElement>
37
+ >(({ className, ...props }, ref) => (
38
+ <div
39
+ ref={ref}
40
+ className={cn(listStyles({ layout: "container" }), className)}
41
+ {...props}
42
+ />
43
+ ));
44
+ NavigationList.displayName = "NavigationList";
45
+
46
+ interface NavigationListItemProps extends React.HTMLAttributes<HTMLDivElement> {
47
+ selected?: boolean;
48
+ label?: string;
49
+ icon?: React.ComponentType;
50
+ }
51
+
52
+ const NavigationListItem = React.forwardRef<
53
+ HTMLDivElement,
54
+ NavigationListItemProps
55
+ >(({ className, selected, label, icon, ...props }, ref) => {
56
+ const [isHovered, setIsHovered] = React.useState(false);
57
+ const [isPressed, setIsPressed] = React.useState(false);
58
+
59
+ const handleMouseDown = (event: React.MouseEvent) => {
60
+ if (!(event.target as HTMLElement).closest(".new-button-class")) {
61
+ setIsPressed(true);
62
+ }
63
+ };
64
+
65
+ return (
66
+ <div className={className} ref={ref} {...props}>
67
+ <div
68
+ className={listStyles({
69
+ layout: "item",
70
+ state: selected ? "selected" : isPressed ? "active" : "unselected",
71
+ })}
72
+ onMouseEnter={() => setIsHovered(true)}
73
+ onMouseLeave={() => {
74
+ setIsHovered(false);
75
+ setIsPressed(false);
76
+ }}
77
+ onMouseDown={handleMouseDown}
78
+ onMouseUp={() => setIsPressed(false)}
79
+ >
80
+ {icon && <Icon visual={icon} size="sm" />}
81
+ {label && (
82
+ <span className="s-grow s-overflow-hidden s-text-ellipsis s-whitespace-nowrap">
83
+ {label}
84
+ </span>
85
+ )}
86
+ {isHovered && (
87
+ <div className="-s-mr-2 s-flex s-h-4 s-items-center">
88
+ <Button
89
+ variant="ghost"
90
+ icon={MoreIcon}
91
+ size="xs"
92
+ onClick={(e) => e.stopPropagation()}
93
+ onMouseDown={(e) => e.stopPropagation()}
94
+ onMouseUp={(e) => e.stopPropagation()}
95
+ />
96
+ </div>
97
+ )}
98
+ </div>
99
+ </div>
100
+ );
101
+ });
102
+ NavigationListItem.displayName = "NavigationListItem";
103
+
104
+ const variantStyles = cva("", {
105
+ variants: {
106
+ variant: {
107
+ primary: "s-text-foreground",
108
+ secondary: "s-text-muted-foreground",
109
+ },
110
+ },
111
+ defaultVariants: {
112
+ variant: "primary",
113
+ },
114
+ });
115
+
116
+ interface NavigationListLabelProps
117
+ extends React.HTMLAttributes<HTMLDivElement>,
118
+ VariantProps<typeof variantStyles> {
119
+ label: string;
120
+ }
121
+
122
+ const NavigationListLabel = React.forwardRef<
123
+ HTMLDivElement,
124
+ NavigationListLabelProps
125
+ >(({ className, variant, label, ...props }, ref) => (
126
+ <div
127
+ ref={ref}
128
+ className={cn(labelStyles(), variantStyles({ variant }), className)}
129
+ {...props}
130
+ >
131
+ {label}
132
+ </div>
133
+ ));
134
+
135
+ NavigationListLabel.displayName = "NavigationListLabel";
136
+
137
+ export { NavigationList, NavigationListItem, NavigationListLabel };
@@ -13,7 +13,7 @@ type ItemVariantType = (typeof ITEM_VARIANTS)[number];
13
13
  export const menuStyleClasses = {
14
14
  inset: "s-pl-8",
15
15
  container: cn(
16
- "s-rounded-lg s-border s-border-hovering s-bg-white s-p-1 s-text-primary-950",
16
+ "s-rounded-xl s-border s-border-hovering s-bg-white s-p-1 s-text-primary-950",
17
17
  "s-z-50 s-min-w-[8rem] s-overflow-hidden",
18
18
  "data-[state=open]:s-animate-in data-[state=closed]:s-animate-out data-[state=closed]:s-fade-out-0 data-[state=open]:s-fade-in-0 data-[state=closed]:s-zoom-out-95 data-[state=open]:s-zoom-in-95 data-[side=bottom]:s-slide-in-from-top-2 data-[side=left]:s-slide-in-from-right-2 data-[side=right]:s-slide-in-from-left-2 data-[side=top]:s-slide-in-from-bottom-2"
19
19
  ),
@@ -83,7 +83,7 @@ const ItemWithLabelIconAndDescription = <
83
83
  return (
84
84
  <>
85
85
  {label && (
86
- <div className="s-grid s-grid-cols-[auto,1fr] s-gap-x-1">
86
+ <div className="s-grid s-grid-cols-[auto,1fr] s-gap-x-1.5">
87
87
  {icon && (
88
88
  <div
89
89
  className={cn(
@@ -38,7 +38,7 @@ const PopoverContent = React.forwardRef<
38
38
  "data-[side=left]:s-slide-in-from-right-2",
39
39
  "data-[side=right]:s-slide-in-from-left-2",
40
40
  "data-[side=top]:s-slide-in-from-bottom-2",
41
- "s-z-50 s-rounded-lg s-border s-bg-background s-text-primary-950 s-shadow-md s-outline-none",
41
+ "s-z-50 s-rounded-xl s-border s-bg-background s-text-primary-950 s-shadow-md s-outline-none",
42
42
  fullWidth ? "s-grow" : "s-w-72 s-p-4",
43
43
  className
44
44
  )}
@@ -46,7 +46,7 @@ const RadioGroup = React.forwardRef<
46
46
  >(({ className, ...props }, ref) => {
47
47
  return (
48
48
  <RadioGroupPrimitive.Root
49
- className={cn("s-grid", className)}
49
+ className={cn("s-grid s-gap-2", className)}
50
50
  {...props}
51
51
  ref={ref}
52
52
  />
@@ -69,34 +69,32 @@ const RadioGroupItem = React.forwardRef<
69
69
  { tooltipMessage, className, size, tooltipAsChild = false, ...props },
70
70
  ref
71
71
  ) => {
72
+ const item = (
73
+ <RadioGroupPrimitive.Item
74
+ ref={ref}
75
+ className={cn(radioStyles({ size }), className)}
76
+ {...props}
77
+ >
78
+ <RadioGroupPrimitive.Indicator
79
+ className={radioIndicatorStyles({ size })}
80
+ />
81
+ </RadioGroupPrimitive.Item>
82
+ );
72
83
  return (
73
- <div className="s-group">
84
+ <div
85
+ className={cn(
86
+ "s-group",
87
+ size === "sm" ? "s-h-5 s-w-5" : "-s-mt-1.5 s-h-4 s-w-4"
88
+ )}
89
+ >
74
90
  {tooltipMessage ? (
75
91
  <Tooltip
76
92
  triggerAsChild={tooltipAsChild}
77
- trigger={
78
- <RadioGroupPrimitive.Item
79
- ref={ref}
80
- className={cn(radioStyles({ size }), className)}
81
- {...props}
82
- >
83
- <RadioGroupPrimitive.Indicator
84
- className={radioIndicatorStyles({ size })}
85
- />
86
- </RadioGroupPrimitive.Item>
87
- }
93
+ trigger={item}
88
94
  label={<span>{tooltipMessage}</span>}
89
95
  />
90
96
  ) : (
91
- <RadioGroupPrimitive.Item
92
- ref={ref}
93
- className={cn(radioStyles({ size }), className)}
94
- {...props}
95
- >
96
- <RadioGroupPrimitive.Indicator
97
- className={radioIndicatorStyles({ size })}
98
- />
99
- </RadioGroupPrimitive.Item>
97
+ item
100
98
  )}
101
99
  </div>
102
100
  );
@@ -47,7 +47,7 @@ const colors: Record<Exclude<SpinnerVariantType, "color">, LottieColorType> = {
47
47
  dark: [0.0588, 0.0902, 0.1647, 1],
48
48
  purple900: [0.298, 0.1137, 0.5843, 1], // #4C1D95
49
49
  pink900: [0.5137, 0.0941, 0.2627, 1], // #831843
50
- slate400: [0.5647, 0.6314, 0.7176, 1], // #94a3b8
50
+ slate400: [0.5804, 0.6392, 0.7216, 1], // #94A3B8
51
51
  };
52
52
 
53
53
  const isColorArray = (arr: unknown): arr is LottieColorType => {
@@ -14,6 +14,7 @@ export interface TreeProps {
14
14
  isLoading?: boolean;
15
15
  tailwindIconTextColor?: string;
16
16
  variant?: "navigator" | "finder";
17
+ className?: string;
17
18
  }
18
19
 
19
20
  export function Tree({
@@ -22,6 +23,7 @@ export function Tree({
22
23
  isBoxed = false,
23
24
  tailwindIconTextColor,
24
25
  variant = "finder",
26
+ className,
25
27
  }: TreeProps) {
26
28
  const modifiedChildren = React.Children.map(children, (child) => {
27
29
  // /!\ Limitation: This stops on the first invalid element.
@@ -44,7 +46,7 @@ export function Tree({
44
46
  });
45
47
 
46
48
  return isLoading ? (
47
- <div className="s-py-2 s-pl-4">
49
+ <div className={cn("s-py-2 s-pl-4", className)}>
48
50
  <Spinner size="xs" variant="dark" />
49
51
  </div>
50
52
  ) : (
@@ -52,7 +54,8 @@ export function Tree({
52
54
  className={cn(
53
55
  "s-flex s-flex-col s-gap-0.5 s-overflow-hidden",
54
56
  isBoxed &&
55
- "s-rounded-xl s-border s-border-structure-200 s-bg-structure-50 s-p-4"
57
+ "s-rounded-xl s-border s-border-structure-200 s-bg-structure-50 s-p-4",
58
+ className
56
59
  )}
57
60
  >
58
61
  {modifiedChildren}
@@ -61,12 +64,11 @@ export function Tree({
61
64
  }
62
65
 
63
66
  const treeItemStyleClasses = {
64
- base: "s-group/tree s-flex s-cursor-default s-flex-row s-items-center s-gap-2 s-py-1.5",
67
+ base: "s-group/tree s-flex s-cursor-default s-flex-row s-items-center s-gap-2 s-py-2",
65
68
  isNavigatableBase:
66
- "s-rounded-lg s-pl-1.5 s-pr-3 s-border s-transition-colors s-duration-300 s-ease-out s-cursor-pointer",
67
- isNavigatableUnselected:
68
- "s-border-structure-200/0 s-bg-white/0 hover:s-border-structure-200 hover:s-bg-white",
69
- isNavigatableSelected: "s-border-structure-200 s-bg-white",
69
+ "s-rounded-xl s-pl-1.5 s-pr-3 s-transition-colors s-duration-300 s-ease-out s-cursor-pointer",
70
+ isNavigatableUnselected: "s-bg-structure-150/0 hover:s-bg-structure-150",
71
+ isNavigatableSelected: "s-font-medium s-bg-structure-150",
70
72
  };
71
73
 
72
74
  interface TreeItemProps {
@@ -172,7 +174,7 @@ Tree.Item = function ({
172
174
  )}
173
175
  {type === "leaf" && <div className="s-w-4 s-flex-shrink-0"></div>}
174
176
  {checkbox && <Checkbox {...checkbox} size="xs" />}
175
- <Icon visual={visual} size="xs" className={tailwindIconTextColor} />
177
+ <Icon visual={visual} size="sm" className={tailwindIconTextColor} />
176
178
  <div
177
179
  className={`s-font-regular s-truncate s-text-sm s-text-element-900 ${labelClassName}`}
178
180
  >
@@ -44,6 +44,11 @@ export { Item } from "./Item";
44
44
  export { Label } from "./Label";
45
45
  export { Markdown } from "./Markdown";
46
46
  export { Modal } from "./Modal";
47
+ export {
48
+ NavigationList,
49
+ NavigationListItem,
50
+ NavigationListLabel,
51
+ } from "./NavigationList";
47
52
  export {
48
53
  NewDropdownMenu,
49
54
  NewDropdownMenuCheckboxItem,
@@ -74,7 +79,7 @@ export {
74
79
  export { Popup } from "./Popup";
75
80
  export { PriceTable } from "./PriceTable";
76
81
  export { RadioGroup, RadioGroupChoice, RadioGroupItem } from "./RadioGroup";
77
- export { ScrollArea } from "./ScrollArea";
82
+ export { ScrollArea, ScrollBar } from "./ScrollArea";
78
83
  export { Searchbar } from "./Searchbar";
79
84
  export { Separator } from "./Separator";
80
85
  export { SliderToggle } from "./SliderToggle";
@@ -17,27 +17,27 @@ export const InputExample = () => (
17
17
  <Input
18
18
  placeholder="placeholder"
19
19
  name="input"
20
- value={"value"}
21
- error={"errored because it's a very long message"}
20
+ value="value"
21
+ error="errored because it's a very long message"
22
22
  showErrorLabel
23
23
  />
24
24
  <Input
25
25
  placeholder="placeholder"
26
26
  name="input"
27
- value={"value"}
28
- error={"errored"}
27
+ value="value"
28
+ error="errored"
29
29
  />
30
30
  <Input
31
31
  placeholder="placeholder"
32
32
  name="input"
33
- value={"value"}
34
- error={"errored because it's a very long message"}
33
+ value="value"
34
+ error="errored because it's a very long message"
35
35
  showErrorLabel
36
36
  />
37
37
  <Input
38
38
  placeholder="placeholder"
39
39
  name="input"
40
- value={"disabled"}
40
+ value="disabled"
41
41
  disabled={true}
42
42
  showErrorLabel
43
43
  />
@@ -47,27 +47,27 @@ export const InputExample = () => (
47
47
  <Input
48
48
  placeholder="placeholder"
49
49
  name="input"
50
- value={"value"}
51
- error={"errored because it's a very long message"}
50
+ value="value"
51
+ error="errored because it's a very long message"
52
52
  showErrorLabel
53
53
  />
54
54
  <Input
55
55
  placeholder="placeholder"
56
56
  name="input"
57
- value={"value"}
58
- error={"errored"}
57
+ value="value"
58
+ error="errored"
59
59
  />
60
60
  <Input
61
61
  placeholder="placeholder"
62
62
  name="input"
63
- value={"value"}
64
- error={"errored because it's a very long message"}
63
+ value="value"
64
+ error="errored because it's a very long message"
65
65
  showErrorLabel
66
66
  />
67
67
  <Input
68
68
  placeholder="placeholder"
69
69
  name="input"
70
- value={"disabled"}
70
+ value="test"
71
71
  showErrorLabel
72
72
  />
73
73
  </div>
@@ -0,0 +1,173 @@
1
+ import type { Meta } from "@storybook/react";
2
+ import React, { useEffect, useState } from "react";
3
+
4
+ import {
5
+ NavigationList,
6
+ NavigationListItem,
7
+ NavigationListLabel,
8
+ ScrollArea,
9
+ ScrollBar,
10
+ } from "../index_with_tw_base";
11
+
12
+ const meta = {
13
+ title: "Primitives/NavigationList",
14
+ } satisfies Meta;
15
+
16
+ export default meta;
17
+
18
+ const getRandomTitles = (count: number) => {
19
+ const shuffled = fakeTitles.sort(() => 0.5 - Math.random());
20
+ return shuffled.slice(0, count);
21
+ };
22
+
23
+ export const NewNavigationListDemo = () => {
24
+ const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
25
+ const [conversationTitles, setConversationTitles] = useState<
26
+ { label: string; items: string[] }[]
27
+ >([]);
28
+
29
+ useEffect(() => {
30
+ // Generate random titles for each date section only once
31
+ setConversationTitles([
32
+ { label: "Today", items: getRandomTitles(5) },
33
+ { label: "Yesterday", items: getRandomTitles(10) },
34
+ ]);
35
+ console.log(conversationTitles); // Add this line
36
+ }, []);
37
+
38
+ // Flatten the items array to easily manage indices
39
+ const allItems = conversationTitles.flatMap((section) => section.items);
40
+
41
+ return (
42
+ <div className="s-h-[400px] s-w-[200px] s-py-12">
43
+ <ScrollArea>
44
+ <NavigationList className="s-w-full">
45
+ {conversationTitles.map((section, sectionIndex) => (
46
+ <React.Fragment key={sectionIndex}>
47
+ <NavigationListLabel label={section.label} />
48
+ {section.items.map((title, index) => {
49
+ const itemIndex = allItems.indexOf(title); // Calculate the global index
50
+ return (
51
+ <NavigationListItem
52
+ key={index}
53
+ selected={itemIndex === selectedIndex}
54
+ onClick={() => setSelectedIndex(itemIndex)}
55
+ label={title}
56
+ className="s-w-full"
57
+ />
58
+ );
59
+ })}
60
+ </React.Fragment>
61
+ ))}
62
+ </NavigationList>
63
+ <ScrollBar />
64
+ </ScrollArea>
65
+ </div>
66
+ );
67
+ };
68
+
69
+ const fakeTitles = [
70
+ "Project Kickoff Meeting",
71
+ "Budget Review Discussion",
72
+ "Weekly Sync with Team",
73
+ "AI Bot Training Session",
74
+ "Quarterly Planning Meeting",
75
+ "Feedback on Latest Design",
76
+ "Client Requirements Gathering",
77
+ "Sprint Retrospective",
78
+ "Daily Standup",
79
+ "Marketing Strategy Planning",
80
+ "Code Review Session",
81
+ "Product Launch Preparation",
82
+ "Onboarding New Team Members",
83
+ "Customer Feedback Analysis",
84
+ "Feature Prioritization Discussion",
85
+ "Technical Debt Assessment",
86
+ "Supply Chain Optimization",
87
+ "Sales Performance Review",
88
+ "Cross-Department Collaboration",
89
+ "Innovation Brainstorming",
90
+ "Risk Management Workshop",
91
+ "Holiday Schedule Planning",
92
+ "Compliance and Security Update",
93
+ "UI/UX Design Critique",
94
+ "End-of-Year Wrap Up",
95
+ "Resource Allocation Meeting",
96
+ "Vendor Negotiation Strategy",
97
+ "Crisis Management Scenario",
98
+ "SEO Best Practices Review",
99
+ "New Hire Orientation",
100
+ "Remote Work Policy Update",
101
+ "Company Values Workshop",
102
+ "Leadership Development Session",
103
+ "Diversity and Inclusion Training",
104
+ "Performance Improvement Plan",
105
+ "Customer Success Story Sharing",
106
+ "Community Engagement Strategy",
107
+ "Internal Product Demo",
108
+ "Cost Reduction Initiative",
109
+ "Change Management Planning",
110
+ "Employee Recognition Program",
111
+ "IT Infrastructure Upgrade",
112
+ "Content Marketing Planning",
113
+ "Team Building Activities",
114
+ "Data Privacy Compliance",
115
+ "Board Meeting Preparation",
116
+ "Investor Relations Update",
117
+ "KPI Tracking and Reporting",
118
+ "Industry Trends Analysis",
119
+ "Partnership Opportunities Exploration",
120
+ "Employee Wellness Program",
121
+ "Talent Acquisition Strategy",
122
+ "Brand Positioning Workshop",
123
+ "Social Media Campaign Planning",
124
+ "Competitive Analysis Review",
125
+ "Legal Compliance Training",
126
+ "Cybersecurity Awareness Session",
127
+ "Cultural Exchange Program",
128
+ "Product Roadmap Presentation",
129
+ "Customer Journey Mapping",
130
+ "Financial Forecasting Session",
131
+ "Brand Storytelling Workshop",
132
+ "AI Ethics and Governance Discussion",
133
+ "Operational Efficiency Assessment",
134
+ "Annual Report Drafting",
135
+ "Project Milestone Celebration",
136
+ "Quality Assurance Review",
137
+ "Public Relations Strategy",
138
+ "Team Performance Metrics",
139
+ "Innovation Lab Tour",
140
+ "Digital Transformation Roadmap",
141
+ "Sustainability Initiatives Planning",
142
+ "Internal Communications Strategy",
143
+ "Customer Advisory Board Meeting",
144
+ "Agile Methodology Training",
145
+ "E-commerce Platform Update",
146
+ "Risk Assessment and Mitigation",
147
+ "Employee Satisfaction Survey Results",
148
+ "Sales Funnel Optimization",
149
+ "Cross-Cultural Communication Training",
150
+ "Global Expansion Strategy",
151
+ "Cloud Migration Plan",
152
+ "Crisis Communication Strategy",
153
+ "Webinar Content Creation",
154
+ "Supply Chain Risk Management",
155
+ "Data Analytics and Insights",
156
+ "Customer Onboarding Process",
157
+ "Brand Awareness Campaign",
158
+ "Product Feature Request Review",
159
+ "Annual Budget Allocation",
160
+ "Employee Exit Interview",
161
+ "User Feedback Session",
162
+ "Strategic Partnership Negotiation",
163
+ "Market Entry Strategy",
164
+ "Employee Handbook Update",
165
+ "Stakeholder Engagement Plan",
166
+ "AI Chatbot Development",
167
+ "Customer Retention Strategy",
168
+ "Company Anniversary Celebration",
169
+ "Leadership Team Offsite",
170
+ "Innovation Challenge Kickoff",
171
+ "Employee Benefits Review",
172
+ "Business Continuity Planning",
173
+ ];