diff --git a/src/components/ai-assistant/AgentBadge.jsx b/src/components/ai-assistant/AgentBadge.tsx
similarity index 97%
rename from src/components/ai-assistant/AgentBadge.jsx
rename to src/components/ai-assistant/AgentBadge.tsx
index fb406b0..f0d9a50 100644
--- a/src/components/ai-assistant/AgentBadge.jsx
+++ b/src/components/ai-assistant/AgentBadge.tsx
@@ -57,8 +57,7 @@ function ConstrainedTag() {
);
}
-/** @param {any} props */
-export function AgentBadge({ page }) {
+export function AgentBadge({ page }: any) {
const { agent, covers } = useActiveAgent();
return (
diff --git a/src/components/ai-assistant/AgentContext.jsx b/src/components/ai-assistant/AgentContext.tsx
similarity index 100%
rename from src/components/ai-assistant/AgentContext.jsx
rename to src/components/ai-assistant/AgentContext.tsx
diff --git a/src/components/ai-assistant/AssistantMessage.jsx b/src/components/ai-assistant/AssistantMessage.tsx
similarity index 98%
rename from src/components/ai-assistant/AssistantMessage.jsx
rename to src/components/ai-assistant/AssistantMessage.tsx
index 8d67fc0..b3d5e59 100644
--- a/src/components/ai-assistant/AssistantMessage.jsx
+++ b/src/components/ai-assistant/AssistantMessage.tsx
@@ -86,9 +86,8 @@ function FeedbackControls({ feedback, onFeedback }) {
}
export const Message = React.memo(
- /** @param {any} props */
({ role, text, blocks, streaming, stopped, onPrompt, onConfirm = null,
- feedback = null, onFeedback = null }) => {
+ feedback = null, onFeedback = null }: any) => {
if (role === 'user') {
return (
diff --git a/src/components/ai-assistant/AssistantPanel.jsx b/src/components/ai-assistant/AssistantPanel.tsx
similarity index 100%
rename from src/components/ai-assistant/AssistantPanel.jsx
rename to src/components/ai-assistant/AssistantPanel.tsx
diff --git a/src/components/ai-assistant/AssistantPanelContext.jsx b/src/components/ai-assistant/AssistantPanelContext.tsx
similarity index 100%
rename from src/components/ai-assistant/AssistantPanelContext.jsx
rename to src/components/ai-assistant/AssistantPanelContext.tsx
diff --git a/src/components/ai-assistant/AssistantTrigger.jsx b/src/components/ai-assistant/AssistantTrigger.tsx
similarity index 98%
rename from src/components/ai-assistant/AssistantTrigger.jsx
rename to src/components/ai-assistant/AssistantTrigger.tsx
index b1bf0b5..cde3c62 100644
--- a/src/components/ai-assistant/AssistantTrigger.jsx
+++ b/src/components/ai-assistant/AssistantTrigger.tsx
@@ -15,8 +15,7 @@ import { useAssistantPanel } from './AssistantPanelContext';
* It self-hides on pages with no assistant, so a page can render it
* unconditionally and never needs to know the placement rules.
*/
-/** @param {any} props */
-export function AssistantTrigger({ className = '', size = 'default' }) {
+export function AssistantTrigger({ className = '', size = 'default' }: any) {
const { supported, isOpen, toggle, context } = useAssistantPanel();
if (!supported) return null;
diff --git a/src/components/ai-assistant/KrowAssistant.jsx b/src/components/ai-assistant/KrowAssistant.tsx
similarity index 100%
rename from src/components/ai-assistant/KrowAssistant.jsx
rename to src/components/ai-assistant/KrowAssistant.tsx
diff --git a/src/components/ai-assistant/PageContext.jsx b/src/components/ai-assistant/PageContext.tsx
similarity index 100%
rename from src/components/ai-assistant/PageContext.jsx
rename to src/components/ai-assistant/PageContext.tsx
diff --git a/src/components/ai-assistant/PromptChips.jsx b/src/components/ai-assistant/PromptChips.tsx
similarity index 99%
rename from src/components/ai-assistant/PromptChips.jsx
rename to src/components/ai-assistant/PromptChips.tsx
index 29fcb68..a718778 100644
--- a/src/components/ai-assistant/PromptChips.jsx
+++ b/src/components/ai-assistant/PromptChips.tsx
@@ -23,14 +23,13 @@ import { cn } from '@/lib/utils';
*
* Arrow keys move between chips, so the whole set is one tab stop.
*/
-/** @param {any} props */
export function PromptChips({
prompts = [], onSelect, max = 0, align = 'center', className = '',
/* Taken out of the tab order while the row is collapsed but still mounted:
a chip inside a zero-height container is invisible, and a Tab that lands on
something invisible is a keyboard user losing their place. */
focusable = true,
-}) {
+}: any) {
const chipRefs = React.useRef([]);
const visible = max ? prompts.slice(0, max) : prompts;
diff --git a/src/components/ai-assistant/PromptInput.jsx b/src/components/ai-assistant/PromptInput.tsx
similarity index 99%
rename from src/components/ai-assistant/PromptInput.jsx
rename to src/components/ai-assistant/PromptInput.tsx
index f2453da..1b346a9 100644
--- a/src/components/ai-assistant/PromptInput.jsx
+++ b/src/components/ai-assistant/PromptInput.tsx
@@ -17,7 +17,6 @@ import { cn } from '@/lib/utils';
* gain — the suggestion chips already teach the range of what can be asked, and
* they do it without a timer or a rerender every four seconds.
*/
-/** @param {any} props */
export function PromptInput({
value,
onChange,
@@ -28,7 +27,7 @@ export function PromptInput({
autoFocus = false,
align = 'left',
className = '',
-}) {
+}: any) {
const textareaRef = React.useRef(null);
const [focused, setFocused] = React.useState(false);
diff --git a/src/components/ai-assistant/ResizeDivider.jsx b/src/components/ai-assistant/ResizeDivider.tsx
similarity index 100%
rename from src/components/ai-assistant/ResizeDivider.jsx
rename to src/components/ai-assistant/ResizeDivider.tsx
diff --git a/src/components/ai-assistant/ResponseBlocks.jsx b/src/components/ai-assistant/ResponseBlocks.tsx
similarity index 95%
rename from src/components/ai-assistant/ResponseBlocks.jsx
rename to src/components/ai-assistant/ResponseBlocks.tsx
index 6d40381..439ccb2 100644
--- a/src/components/ai-assistant/ResponseBlocks.jsx
+++ b/src/components/ai-assistant/ResponseBlocks.tsx
@@ -121,14 +121,14 @@ const TONE_BADGE = {
/* ── Individual blocks ──────────────────────────────────────────────────── */
-const TextBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const TextBlock = React.memo(({ block }: any) => (
));
TextBlock.displayName = 'TextBlock';
-const HeadingBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const HeadingBlock = React.memo(({ block }: any) => (
{block.text}
{block.sub &&
{block.sub}
}
@@ -137,7 +137,7 @@ const HeadingBlock = React.memo(/** @param {any} props */ ({ block }) => (
HeadingBlock.displayName = 'HeadingBlock';
/** Headline figures. Two columns keeps the numbers large in a 380px panel. */
-const KpisBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const KpisBlock = React.memo(({ block }: any) => (
{block.items.map((item) => (
(
KpisBlock.displayName = 'KpisBlock';
/** Pass/warn checks. The icon carries the state so colour is not the only cue. */
-const StatusBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const StatusBlock = React.memo(({ block }: any) => (
{block.items.map((item) => (
-
@@ -204,7 +204,7 @@ const StatusBlock = React.memo(/** @param {any} props */ ({ block }) => (
));
StatusBlock.displayName = 'StatusBlock';
-const MetersBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const MetersBlock = React.memo(({ block }: any) => (
{block.items.map((item) => (
@@ -226,7 +226,7 @@ MetersBlock.displayName = 'MetersBlock';
* A table. Scrolls horizontally inside its own container so a wide comparison
* never widens the panel.
*/
-const TableBlock = React.memo(/** @param {any} props */ ({ block }) => {
+const TableBlock = React.memo(({ block }: any) => {
const cell = (value) => {
if (value == null || value === '') return
—;
if (typeof value === 'object') {
@@ -287,7 +287,7 @@ const TableBlock = React.memo(/** @param {any} props */ ({ block }) => {
TableBlock.displayName = 'TableBlock';
/** Stage progression, widths relative to the largest stage. */
-const FunnelBlock = React.memo(/** @param {any} props */ ({ block }) => {
+const FunnelBlock = React.memo(({ block }: any) => {
const max = Math.max(...block.steps.map((s) => s.count), 1);
return (
@@ -314,7 +314,7 @@ const FunnelBlock = React.memo(/** @param {any} props */ ({ block }) => {
});
FunnelBlock.displayName = 'FunnelBlock';
-const ListBlock = React.memo(/** @param {any} props */ ({ block }) => {
+const ListBlock = React.memo(({ block }: any) => {
const Tag = block.ordered ? 'ol' : 'ul';
return (
@@ -357,7 +357,7 @@ ListBlock.displayName = 'ListBlock';
* clickable and doing nothing. An item may carry a hint *and* an action: the
* hint explains the record, the action opens it.
*/
-const InsightsBlock = React.memo(/** @param {any} props */ ({ block, onPrompt }) => (
+const InsightsBlock = React.memo(({ block, onPrompt }: any) => (
{block.items.map((item, i) => {
const surface = cn(
@@ -434,7 +434,7 @@ const InsightsBlock = React.memo(/** @param {any} props */ ({ block, onPrompt })
InsightsBlock.displayName = 'InsightsBlock';
/** Recommended steps — numbered, because order is the recommendation. */
-const ActionsBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const ActionsBlock = React.memo(({ block }: any) => (
{block.items.map((item, i) => (
-
@@ -453,7 +453,7 @@ const ActionsBlock = React.memo(/** @param {any} props */ ({ block }) => (
));
ActionsBlock.displayName = 'ActionsBlock';
-const BadgesBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const BadgesBlock = React.memo(({ block }: any) => (
{block.items.map((item) => (
@@ -464,7 +464,7 @@ const BadgesBlock = React.memo(/** @param {any} props */ ({ block }) => (
));
BadgesBlock.displayName = 'BadgesBlock';
-const TimelineBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const TimelineBlock = React.memo(({ block }: any) => (
{block.items.map((item, i) => (
-
@@ -497,7 +497,7 @@ const TimelineBlock = React.memo(/** @param {any} props */ ({ block }) => (
));
TimelineBlock.displayName = 'TimelineBlock';
-const NoteBlock = React.memo(/** @param {any} props */ ({ block }) => (
+const NoteBlock = React.memo(({ block }: any) => (
@@ -514,7 +514,7 @@ NoteBlock.displayName = 'NoteBlock';
* shape the table does not carry renders nothing rather than something
* improvised.
*/
-const SkillSectionBlock = React.memo(/** @param {any} props */ ({ block }) => {
+const SkillSectionBlock = React.memo(({ block }: any) => {
const section = block.section;
const Component = SECTION_COMPONENTS[section?.shape || section?.type];
@@ -564,7 +564,7 @@ SkillSectionBlock.displayName = 'SkillSectionBlock';
* - **Not pretend to be finished.** Once approved, the block stays visible
* and says so. Replacing it with a tick would lose what was agreed to.
*/
-const ConfirmationBlock = React.memo(/** @param {any} props */ ({ block, onConfirm }) => {
+const ConfirmationBlock = React.memo(({ block, onConfirm }: any) => {
const [state, setState] = React.useState('pending');
const approve = React.useCallback(() => {
@@ -673,7 +673,7 @@ const RENDERERS = {
* blocks has consistent rhythm — a heading hugs what follows it, everything
* else breathes.
*/
-export const ResponseDocument = React.memo(/** @param {any} props */ ({ blocks = [], streaming = false, onPrompt, onConfirm }) => (
+export const ResponseDocument = React.memo(({ blocks = [], streaming = false, onPrompt, onConfirm }: any) => (
{blocks.map((block, i) => {
const Renderer = RENDERERS[block.type];
diff --git a/src/components/ai-assistant/index.jsx b/src/components/ai-assistant/index.tsx
similarity index 100%
rename from src/components/ai-assistant/index.jsx
rename to src/components/ai-assistant/index.tsx