indas-ui 0.1.11 → 0.1.13

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.
@@ -14,7 +14,7 @@ const utils_1 = require("../../lib/utils.js");
14
14
  const LanguageContext_1 = require("../../contexts/LanguageContext.js");
15
15
  /** What the paperclip offers when the host does not say: images, PDFs and documents. */
16
16
  exports.DEFAULT_CHAT_ACCEPT = 'image/*,application/pdf,.doc,.docx,.txt';
17
- function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = exports.DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', attachIcon, compact = false, disabled = false, disabledReason }) {
17
+ function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = exports.DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', attachIcon, speechLang = 'en-IN', compact = false, disabled = false, disabledReason }) {
18
18
  // Optional: the composer is exported for host apps that have no LanguageProvider, and falls
19
19
  // back to the English source text rather than throwing.
20
20
  const { t } = (0, LanguageContext_1.useOptionalLanguage)();
@@ -43,7 +43,7 @@ function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'S
43
43
  const recognition = new SpeechRecognition();
44
44
  recognition.continuous = false;
45
45
  recognition.interimResults = false;
46
- recognition.lang = 'en-IN';
46
+ recognition.lang = speechLang;
47
47
  recognition.onresult = (event) => {
48
48
  const transcript = event.results[0]?.[0]?.transcript;
49
49
  if (transcript) {
@@ -69,7 +69,7 @@ function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'S
69
69
  setIsListening(false);
70
70
  recognitionRef.current = null;
71
71
  }
72
- }, [isListening]);
72
+ }, [isListening, speechLang]);
73
73
  // Cleanup on unmount
74
74
  (0, react_1.useEffect)(() => {
75
75
  return () => { recognitionRef.current?.abort(); };
@@ -438,7 +438,7 @@ function FilterBar({ title, contextLabel, description, secondaryToggle, timeFilt
438
438
  onTimeFilterSelectionChange?.(newSelection);
439
439
  } }) })), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-0.5 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] p-0.5", children: [!hideFilterButton && ((0, jsx_runtime_1.jsxs)("div", { className: "relative", children: [(0, jsx_runtime_1.jsxs)("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: (0, utils_1.cn)('w-7 h-7 rounded-md flex items-center justify-center transition-colors relative', popoverOpen
440
440
  ? 'bg-[rgb(var(--color-primary))] text-white shadow-sm'
441
- : 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), (!hideTimeFilter || secondaryToggle) && ((0, jsx_runtime_1.jsxs)("div", { className: "sm:hidden mt-2 flex flex-col items-start gap-2", children: [secondaryToggle && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
441
+ : 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && ((0, jsx_runtime_1.jsx)("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && ((0, jsx_runtime_1.jsxs)("div", { ref: popoverRef, className: (0, utils_1.cn)('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "p-3 space-y-3", children: [filters.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => ((0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), (0, jsx_runtime_1.jsx)(dropdown_1.Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && ((0, jsx_runtime_1.jsx)(date_picker_1.DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && ((0, jsx_runtime_1.jsx)(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && ((0, jsx_runtime_1.jsx)(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && ((0, jsx_runtime_1.jsx)("button", { onClick: onApply, className: (0, utils_1.cn)('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), (!hideTimeFilter || secondaryToggle) && ((0, jsx_runtime_1.jsxs)("div", { className: "sm:hidden mt-2 -mx-1 flex items-center gap-2 overflow-x-auto px-1 pb-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [&>*]:shrink-0", children: [secondaryToggle && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && ((0, jsx_runtime_1.jsx)(tabs_1.Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
442
442
  Day: timeFilterSelection?.days || [],
443
443
  Week: timeFilterSelection?.weeks || [],
444
444
  Month: timeFilterSelection?.months || [],
@@ -25,9 +25,11 @@ interface MultimodalInputProps {
25
25
  * picker (a menu, a scan) may pass a plus. Sized by the host, e.g. `<Plus className="w-4 h-4" />`.
26
26
  */
27
27
  attachIcon?: ReactNode;
28
+ /** The language the mic listens in, as a BCP 47 tag: 'en-IN' (default), 'hi-IN' for Hindi. */
29
+ speechLang?: string;
28
30
  compact?: boolean;
29
31
  disabled?: boolean;
30
32
  disabledReason?: string;
31
33
  }
32
- export declare function MultimodalInput({ onSubmit, onStop, isLoading, placeholder, allowFileUpload, accept, multiple, attachLabel, attachIcon, compact, disabled, disabledReason }: MultimodalInputProps): import("react").JSX.Element;
34
+ export declare function MultimodalInput({ onSubmit, onStop, isLoading, placeholder, allowFileUpload, accept, multiple, attachLabel, attachIcon, speechLang, compact, disabled, disabledReason }: MultimodalInputProps): import("react").JSX.Element;
33
35
  export {};
@@ -10,7 +10,7 @@ import { cn } from '../../lib/utils.js';
10
10
  import { useOptionalLanguage } from '../../contexts/LanguageContext.js';
11
11
  /** What the paperclip offers when the host does not say: images, PDFs and documents. */
12
12
  export const DEFAULT_CHAT_ACCEPT = 'image/*,application/pdf,.doc,.docx,.txt';
13
- export function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', attachIcon, compact = false, disabled = false, disabledReason }) {
13
+ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', attachIcon, speechLang = 'en-IN', compact = false, disabled = false, disabledReason }) {
14
14
  // Optional: the composer is exported for host apps that have no LanguageProvider, and falls
15
15
  // back to the English source text rather than throwing.
16
16
  const { t } = useOptionalLanguage();
@@ -39,7 +39,7 @@ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placehold
39
39
  const recognition = new SpeechRecognition();
40
40
  recognition.continuous = false;
41
41
  recognition.interimResults = false;
42
- recognition.lang = 'en-IN';
42
+ recognition.lang = speechLang;
43
43
  recognition.onresult = (event) => {
44
44
  const transcript = event.results[0]?.[0]?.transcript;
45
45
  if (transcript) {
@@ -65,7 +65,7 @@ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placehold
65
65
  setIsListening(false);
66
66
  recognitionRef.current = null;
67
67
  }
68
- }, [isListening]);
68
+ }, [isListening, speechLang]);
69
69
  // Cleanup on unmount
70
70
  useEffect(() => {
71
71
  return () => { recognitionRef.current?.abort(); };
@@ -432,7 +432,7 @@ export function FilterBar({ title, contextLabel, description, secondaryToggle, t
432
432
  onTimeFilterSelectionChange?.(newSelection);
433
433
  } }) })), _jsxs("div", { className: "flex items-center gap-0.5 rounded-lg border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] p-0.5", children: [!hideFilterButton && (_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: buttonRef, onClick: () => setPopoverOpen(!popoverOpen), className: cn('w-7 h-7 rounded-md flex items-center justify-center transition-colors relative', popoverOpen
434
434
  ? 'bg-[rgb(var(--color-primary))] text-white shadow-sm'
435
- : 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [_jsx(ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && (_jsx("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && (_jsxs("div", { ref: popoverRef, className: cn('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [_jsxs("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), _jsx("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: _jsx(X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), _jsxs("div", { className: "p-3 space-y-3", children: [filters.length > 0 && (_jsx("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => (_jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), _jsx(Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && (_jsx(DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && (_jsx(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && (_jsx(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && (_jsx("button", { onClick: onApply, className: cn('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), (!hideTimeFilter || secondaryToggle) && (_jsxs("div", { className: "sm:hidden mt-2 flex flex-col items-start gap-2", children: [secondaryToggle && (_jsx(Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && (_jsx(Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
435
+ : 'text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]'), title: "Filters", children: [_jsx(ListFilter, { className: "w-4 h-4" }), hasActiveFilters && !popoverOpen && (_jsx("span", { className: "absolute -top-1 -right-1 w-2 h-2 bg-[rgb(var(--color-primary))] rounded-full" }))] }), popoverOpen && (_jsxs("div", { ref: popoverRef, className: cn('absolute top-full right-0 mt-2 z-50', 'w-[95vw] sm:w-auto', 'bg-[rgb(var(--bg-surface))] rounded-xl shadow-xl border border-[rgb(var(--bd-default))]', 'overflow-hidden'), children: [_jsxs("div", { className: "px-3 py-2 border-b border-[rgb(var(--bd-default))] flex items-center justify-between", children: [_jsx("span", { className: "text-xs font-semibold text-[rgb(var(--fg-default))]", children: "Filters" }), _jsx("button", { onClick: () => setPopoverOpen(false), className: "w-5 h-5 rounded flex items-center justify-center hover:bg-[rgb(var(--bg-subtle))] transition-colors", children: _jsx(X, { className: "w-3 h-3 text-[rgb(var(--fg-muted))]" }) })] }), _jsxs("div", { className: "p-3 space-y-3", children: [filters.length > 0 && (_jsx("div", { className: "grid gap-3", style: { gridTemplateColumns: `repeat(${Math.min(filters.length, 3)}, minmax(140px, 1fr))` }, children: filters.map((filter) => (_jsxs("div", { children: [_jsx("label", { className: "text-[10px] font-semibold text-[rgb(var(--fg-muted))] uppercase tracking-wider mb-1 block", children: filter.label }), _jsx(Dropdown, { options: filter.options, multiSelect: filter.type === 'multiselect', value: filterValues[filter.id] ?? (filter.type === 'multiselect' ? [] : ''), onValueChange: (value) => onFilterChange?.(filter.id, value), placeholder: filter.placeholder || `All ${filter.label}s`, searchable: true, className: "w-full" })] }, filter.id))) })), children, !hideDateRange && (_jsx(DatePicker, { mode: "range", value: dateRangeValue, onChange: handleDateRangeChange, inline: true }))] })] }))] })), forecast && onForecastChange && (_jsx(ForecastControl, { forecast: forecast, onForecastChange: onForecastChange, timeFilter: timeFilter, onTimeFilterChange: onTimeFilterChange, bare: true })), (showInsights || reports.length > 0 || onShare || onExport) && (_jsx(OverflowMenu, { showInsights: showInsights, insightsActive: insightsActive, onInsightsClick: onInsightsClick, reports: reports, onReportSelect: onReportSelect, onShare: onShare, onExport: onExport }))] }), showApplyButton && (_jsx("button", { onClick: onApply, className: cn('h-8 px-4 rounded-md flex items-center gap-1.5', 'bg-[rgb(var(--color-primary))] text-white', 'text-xs font-semibold', 'shadow-sm hover:shadow-md transition-all', 'hover:brightness-110'), children: "Apply" }))] })] }), (!hideTimeFilter || secondaryToggle) && (_jsxs("div", { className: "sm:hidden mt-2 -mx-1 flex items-center gap-2 overflow-x-auto px-1 pb-0.5 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [&>*]:shrink-0", children: [secondaryToggle && (_jsx(Tabs, { tabs: secondaryToggle.options.map(opt => ({ id: opt.value, label: opt.label })), activeTab: secondaryToggle.value, onTabChange: secondaryToggle.onChange, size: "sm" })), !hideTimeFilter && (_jsx(Tabs, { tabs: timeOptions.map(opt => ({ id: opt.value, label: opt.label, dropdownOptions: opt.dropdownOptions, quickOptions: opt.quickOptions })), activeTab: timeFilter, onTabChange: (tabId) => onTimeFilterChange?.(tabId), variant: "rounded", size: "sm", dropdownValues: {
436
436
  Day: timeFilterSelection?.days || [],
437
437
  Week: timeFilterSelection?.weeks || [],
438
438
  Month: timeFilterSelection?.months || [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indas-ui",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Indas UI — React component library for business apps: Tailwind design tokens, Radix primitives, Lucide icons, DataGrid, dashboards and charts.",
5
5
  "license": "MIT",
6
6
  "author": "Indas Analytics Pvt Ltd",