impact-nova 2.6.0-alpha.0 → 2.6.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.
- package/README.md +25 -27
- package/dist/components/data/ag-grid-react/ag-grid.types.d.ts +3 -28
- package/dist/components/data/ag-grid-react/cell-renderers/date-display-renderer.d.ts +3 -0
- package/dist/components/data/ag-grid-react/cell-renderers/date-display-renderer.js +38 -31
- package/dist/components/data/ag-grid-react/cell-renderers/input-display-renderer.d.ts +1 -1
- package/dist/components/data/ag-grid-react/headers/advanced-filter/advanced-filter-dialog.js +65 -75
- package/dist/components/data/ag-grid-react/headers/advanced-filter/column-filter-section.d.ts +1 -1
- package/dist/components/data/ag-grid-react/headers/advanced-filter/column-filter-section.js +54 -54
- package/dist/components/data/ag-grid-react/headers/components/date-filter-picker.d.ts +1 -1
- package/dist/components/data/ag-grid-react/headers/components/header-info.d.ts +9 -3
- package/dist/components/data/ag-grid-react/headers/components/header-info.js +69 -61
- package/dist/components/data/ag-grid-react/headers/components/info-modal.js +8 -8
- package/dist/components/data/ag-grid-react/headers/header-search-input.js +119 -122
- package/dist/components/data/ag-grid-react/headers/utils/date-utils.d.ts +1 -2
- package/dist/components/data/ag-grid-react/headers/utils/date-utils.js +20 -25
- package/dist/components/data/ag-grid-react/headers/utils/filter-utils.d.ts +1 -1
- package/dist/components/data/ag-grid-react/index.d.ts +1 -1
- package/dist/components/data/ag-grid-react/index.js +254 -481
- package/dist/components/data/ag-grid-react/theme.js +2 -6
- package/dist/components/data/ag-grid-react/value-formatter.types.d.ts +0 -4
- package/dist/components/data/ag-grid-react/value-formatters.d.ts +19 -0
- package/dist/components/data/ag-grid-react/value-formatters.js +90 -88
- package/dist/components/data/data-table/build-column-tree-from-grid.d.ts +2 -0
- package/dist/components/data/data-table/build-column-tree-from-grid.js +64 -58
- package/dist/components/data/data-table/column-picker-authority.d.ts +35 -0
- package/dist/components/data/data-table/column-picker-authority.js +118 -0
- package/dist/components/data/data-table/column-picker-drop-validation.d.ts +7 -0
- package/dist/components/data/data-table/column-picker-drop-validation.js +37 -0
- package/dist/components/data/data-table/column-savability.d.ts +3 -0
- package/dist/components/data/data-table/column-savability.js +10 -0
- package/dist/components/data/data-table/data-table-column-apply.d.ts +2 -0
- package/dist/components/data/data-table/data-table-column-apply.js +84 -73
- package/dist/components/data/data-table/data-table-column-def-pin.js +31 -34
- package/dist/components/data/data-table/data-table-column-list-tree-apply.d.ts +10 -0
- package/dist/components/data/data-table/data-table-column-list-tree-apply.js +79 -0
- package/dist/components/data/data-table/data-table-column-list.js +122 -64
- package/dist/components/data/data-table/data-table-column-tree-cache.d.ts +12 -6
- package/dist/components/data/data-table/data-table-column-tree-cache.js +250 -131
- package/dist/components/data/data-table/data-table-context.js +5 -5
- package/dist/components/data/data-table/data-table-flat-column-virtual-rows.d.ts +27 -0
- package/dist/components/data/data-table/data-table-flat-column-virtual-rows.js +196 -0
- package/dist/components/data/data-table/data-table-picker-column-eligibility.d.ts +1 -0
- package/dist/components/data/data-table/data-table-picker-column-eligibility.js +7 -0
- package/dist/components/data/data-table/data-table-sheet-context.js +1 -1
- package/dist/components/data/data-table/data-table-sheet.js +1 -2
- package/dist/components/data/data-table/index.d.ts +2 -0
- package/dist/components/data/data-table/index.js +32 -28
- package/dist/components/data/data-table/patch-column-tree-indicators-from-grid.d.ts +5 -0
- package/dist/components/data/data-table/patch-column-tree-indicators-from-grid.js +28 -10
- package/dist/components/data/data-table/reconcile-column-tree-from-grid.d.ts +12 -0
- package/dist/components/data/data-table/reconcile-column-tree-from-grid.js +12 -0
- package/dist/components/data/data-table/use-data-table-column-list-sync.d.ts +10 -0
- package/dist/components/data/data-table/use-data-table-column-list-sync.js +250 -196
- package/dist/components/data/nested-list/components/NestedListContent.d.ts +10 -2
- package/dist/components/data/nested-list/components/NestedListContent.js +253 -138
- package/dist/components/data/nested-list/components/SortableItem.d.ts +2 -1
- package/dist/components/data/nested-list/components/SortableItem.js +62 -60
- package/dist/components/data/nested-list/hooks/useNestedListDragDrop.d.ts +10 -20
- package/dist/components/data/nested-list/hooks/useNestedListDragDrop.js +44 -233
- package/dist/components/data/nested-list/hooks/useVirtualNestedListDrag.d.ts +24 -0
- package/dist/components/data/nested-list/hooks/useVirtualNestedListDrag.js +128 -0
- package/dist/components/data/nested-list/nested-list-constants.d.ts +4 -1
- package/dist/components/data/nested-list/nested-list-constants.js +10 -4
- package/dist/components/data/nested-list/nested-list-display-utils.d.ts +11 -0
- package/dist/components/data/nested-list/nested-list-display-utils.js +74 -0
- package/dist/components/data/nested-list/nested-list-drop-engine.d.ts +31 -0
- package/dist/components/data/nested-list/nested-list-drop-engine.js +209 -0
- package/dist/components/data/nested-list/nested-list-flat-virtual-handlers.d.ts +26 -0
- package/dist/components/data/nested-list/nested-list-flat-virtual-handlers.js +67 -0
- package/dist/components/data/nested-list/nested-list-item-tree-mutations.d.ts +4 -0
- package/dist/components/data/nested-list/nested-list-item-tree-mutations.js +43 -0
- package/dist/components/data/nested-list/nested-list-lazy-flat-rows.d.ts +3 -0
- package/dist/components/data/nested-list/nested-list-lazy-flat-rows.js +34 -0
- package/dist/components/data/nested-list/nested-list-row-estimates.d.ts +9 -0
- package/dist/components/data/nested-list/nested-list-row-estimates.js +14 -0
- package/dist/components/data/nested-list/nested-list-scroll-anchor.d.ts +36 -0
- package/dist/components/data/nested-list/nested-list-scroll-anchor.js +47 -0
- package/dist/components/data/nested-list/nested-list-virtual-drop.d.ts +59 -0
- package/dist/components/data/nested-list/nested-list-virtual-drop.js +341 -0
- package/dist/components/data/nested-list/nested-list.js +322 -336
- package/dist/components/data/nested-list/nested-list.types.d.ts +17 -0
- package/dist/components/data-display/calendar/calendar-available-view.d.ts +6 -2
- package/dist/components/data-display/calendar/calendar-available-view.js +18 -19
- package/dist/components/data-display/calendar/calendar-config.js +21 -22
- package/dist/components/data-display/calendar/calendar-day-button.js +21 -21
- package/dist/components/data-display/calendar/calendar-day-picker-view.js +35 -36
- package/dist/components/data-display/calendar/calendar-fiscal-labels.d.ts +3 -3
- package/dist/components/data-display/calendar/calendar-fiscal-labels.js +62 -50
- package/dist/components/data-display/calendar/calendar-quarter-utils.js +12 -12
- package/dist/components/data-display/calendar/calendar-week-utils.d.ts +6 -0
- package/dist/components/data-display/calendar/calendar-week-utils.js +33 -33
- package/dist/components/data-display/calendar/calendar-year-panes.js +68 -58
- package/dist/components/data-display/calendar/calendar-year-utils.d.ts +13 -0
- package/dist/components/data-display/calendar/calendar-year-utils.js +59 -50
- package/dist/components/data-display/calendar/calendar.js +156 -153
- package/dist/components/data-display/calendar/fiscal-period-caption-select.js +22 -23
- package/dist/components/data-display/calendar/use-calendar-i18n.d.ts +0 -1
- package/dist/components/data-display/calendar/use-calendar-i18n.js +9 -10
- package/dist/components/data-display/chart/chart.js +72 -72
- package/dist/components/data-display/chart/chart.utils.d.ts +1 -1
- package/dist/components/data-display/chart/chart.utils.js +31 -40
- package/dist/components/feedback/sheet/sheet.js +1 -1
- package/dist/components/feedback/toast/toast.d.ts +1 -1
- package/dist/components/feedback/toast/toast.variants.d.ts +1 -1
- package/dist/components/flows/filter-panel/filter-panel.d.ts +1 -1
- package/dist/components/flows/filter-panel/filter-panel.js +64 -65
- package/dist/components/flows/filter-panel/filter-panel.types.d.ts +0 -1
- package/dist/components/flows/guidance/guidance-layer.js +34 -31
- package/dist/components/flows/guidance/hooks/useGuidanceOverlayGeometry.js +29 -20
- package/dist/components/flows/guidance/renderers/announcement-renderer.d.ts +1 -1
- package/dist/components/flows/guidance/renderers/announcement-renderer.js +74 -28
- package/dist/components/flows/guidance/renderers/guidance-action-tap-icon.d.ts +5 -0
- package/dist/components/flows/guidance/renderers/guidance-action-tap-icon.js +68 -0
- package/dist/components/flows/guidance/renderers/guidance-announcement-surface.d.ts +5 -0
- package/dist/components/flows/guidance/renderers/guidance-announcement-surface.js +76 -0
- package/dist/components/flows/guidance/renderers/guidance-card-shared.d.ts +43 -2
- package/dist/components/flows/guidance/renderers/guidance-card-shared.js +322 -99
- package/dist/components/flows/guidance/renderers/guidance-renderer-shared.d.ts +3 -0
- package/dist/components/flows/guidance/renderers/guidance-renderer-shared.js +189 -148
- package/dist/components/flows/guidance/renderers/guidance-shortcut-display.d.ts +9 -0
- package/dist/components/flows/guidance/renderers/guidance-shortcut-display.js +36 -0
- package/dist/components/flows/guidance/renderers/guidance-tour-overlay.d.ts +2 -1
- package/dist/components/flows/guidance/renderers/guidance-tour-overlay.js +152 -89
- package/dist/components/forms/date-picker/date-picker.js +126 -125
- package/dist/components/forms/date-picker/date-range-picker.js +192 -191
- package/dist/components/forms/date-picker/fiscal-pass-through.d.ts +6 -6
- package/dist/components/forms/date-picker/fiscal-pass-through.js +7 -3
- package/dist/components/forms/date-picker/multi-date-picker.js +67 -66
- package/dist/components/forms/date-picker/multi-quarter-picker.js +87 -87
- package/dist/components/forms/date-picker/multi-week-picker.js +83 -82
- package/dist/components/forms/date-picker/multi-year-picker.js +81 -81
- package/dist/components/forms/date-picker/quarter-range-picker.js +84 -84
- package/dist/components/forms/date-picker/week-picker.js +175 -174
- package/dist/components/forms/date-picker/week-range-picker.js +214 -213
- package/dist/components/forms/date-picker/year-range-picker.js +79 -79
- package/dist/components/ui/local-raster-icons/rasterIcons.d.ts +0 -1
- package/dist/components/ui/local-raster-icons/rasterIcons.js +25 -27
- package/dist/form-react/Fields/ChipsField.js +49 -48
- package/dist/form-react/Fields/DateRangeField.js +25 -25
- package/dist/form-react/Fields/MonthRangeField.js +57 -57
- package/dist/form-react/Fields/MultiMonthPickerField.js +28 -26
- package/dist/form-react/Fields/MultiWeekPickerField.js +41 -38
- package/dist/form-react/Fields/MultiYearPickerField.js +45 -45
- package/dist/form-react/Fields/SelectField.js +24 -26
- package/dist/form-react/Fields/TextFieldWithBackendValidation.js +27 -26
- package/dist/form-react/Fields/WeekRangePicker.js +18 -16
- package/dist/form-react/Fields/YearPickerField.js +27 -27
- package/dist/form-react/Fields/YearRangePickerField.js +29 -29
- package/dist/form-react/fields.d.ts +3 -0
- package/dist/form-react/fields.js +35 -29
- package/dist/form-react/types/fields.types.d.ts +39 -0
- package/dist/form-react/utils/date.utils.d.ts +52 -2
- package/dist/form-react/utils/date.utils.js +198 -62
- package/dist/i18n/defaultMessages.d.ts +5 -143
- package/dist/i18n/defaultMessages.js +25 -163
- package/dist/i18n/getDateFnsLocale.d.ts +4 -5
- package/dist/i18n/getDateFnsLocale.js +16 -46
- package/dist/i18n/i18n.types.d.ts +0 -13
- package/dist/i18n/impact-nova-i18n-context.d.ts +1 -1
- package/dist/i18n/impact-nova-i18n-context.js +25 -33
- package/dist/i18n/impact-nova-i18n-defaults.js +6 -8
- package/dist/i18n/index.d.ts +1 -4
- package/dist/i18n/index.js +16 -41
- package/dist/i18n/locales/de.js +3 -141
- package/dist/i18n/locales/es.js +3 -141
- package/dist/i18n/locales/hi.js +3 -141
- package/dist/i18n/locales/kn.js +3 -141
- package/dist/impact-nova-components.css +0 -249
- package/dist/impact-nova-tokens.scss +22 -6
- package/dist/impact-nova.css +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +603 -622
- package/dist/lib/fiscal-calendar/index.d.ts +2 -2
- package/dist/lib/fiscal-calendar/index.js +26 -24
- package/dist/lib/fiscal-calendar/week-selection.d.ts +5 -0
- package/dist/lib/fiscal-calendar/week-selection.js +56 -49
- package/dist/lib/guidance/engine/guidance-engine.d.ts +9 -0
- package/dist/lib/guidance/engine/guidance-engine.js +127 -65
- package/dist/lib/guidance/engine/manifest-validator.js +37 -30
- package/dist/lib/guidance/targets/target-resolver.d.ts +1 -1
- package/dist/lib/guidance/targets/target-resolver.js +32 -30
- package/dist/lib/guidance/types/guidance.types.d.ts +41 -0
- package/dist/lib/hash/fnv1a128.d.ts +16 -0
- package/dist/lib/hash/fnv1a128.js +21 -0
- package/dist/llms/index.js +2 -26
- package/dist/llms/rules/ag-grid.js +1 -1
- package/dist/llms/rules/best-practices.js +1 -1
- package/dist/llms/rules/installation.js +1 -1
- package/dist/llms/rules/migration.js +1 -1
- package/dist/llms/rules/real-world-patterns.js +1 -1
- package/dist/llms/rules/requirements.js +1 -1
- package/dist/llms/rules/troubleshooting.js +1 -1
- package/dist/providers/app-providers.d.ts +1 -3
- package/dist/providers/app-providers.js +11 -22
- package/package.json +2 -13
- package/dist/components/data/ag-grid-react/chat/chat-capabilities.d.ts +0 -9
- package/dist/components/data/ag-grid-react/chat/chat-capabilities.js +0 -22
- package/dist/components/data/ag-grid-react/chat/chat-column.d.ts +0 -20
- package/dist/components/data/ag-grid-react/chat/chat-column.js +0 -81
- package/dist/components/data/ag-grid-react/chat/chat-composer.d.ts +0 -10
- package/dist/components/data/ag-grid-react/chat/chat-composer.js +0 -352
- package/dist/components/data/ag-grid-react/chat/chat-constants.d.ts +0 -17
- package/dist/components/data/ag-grid-react/chat/chat-constants.js +0 -22
- package/dist/components/data/ag-grid-react/chat/chat-format.d.ts +0 -41
- package/dist/components/data/ag-grid-react/chat/chat-format.js +0 -94
- package/dist/components/data/ag-grid-react/chat/chat-host.d.ts +0 -10
- package/dist/components/data/ag-grid-react/chat/chat-host.js +0 -651
- package/dist/components/data/ag-grid-react/chat/chat-host.types.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-html.d.ts +0 -2
- package/dist/components/data/ag-grid-react/chat/chat-html.js +0 -40
- package/dist/components/data/ag-grid-react/chat/chat-identity.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-identity.js +0 -24
- package/dist/components/data/ag-grid-react/chat/chat-menu.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-menu.js +0 -15
- package/dist/components/data/ag-grid-react/chat/chat-notify.d.ts +0 -17
- package/dist/components/data/ag-grid-react/chat/chat-notify.js +0 -124
- package/dist/components/data/ag-grid-react/chat/chat-persist.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-persist.js +0 -34
- package/dist/components/data/ag-grid-react/chat/chat-priority.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-priority.js +0 -79
- package/dist/components/data/ag-grid-react/chat/chat-summaries.d.ts +0 -2
- package/dist/components/data/ag-grid-react/chat/chat-summaries.js +0 -24
- package/dist/components/data/ag-grid-react/chat/chat-thread-ui.d.ts +0 -72
- package/dist/components/data/ag-grid-react/chat/chat-thread-ui.js +0 -713
- package/dist/components/data/ag-grid-react/chat/chat-toggle.d.ts +0 -6
- package/dist/components/data/ag-grid-react/chat/chat-toggle.js +0 -25
- package/dist/components/data/ag-grid-react/chat/chat-ui-actions.d.ts +0 -13
- package/dist/components/data/ag-grid-react/chat/chat-ui-actions.js +0 -26
- package/dist/components/data/ag-grid-react/chat/chat-window.d.ts +0 -14
- package/dist/components/data/ag-grid-react/chat/chat-window.js +0 -82
- package/dist/components/data/ag-grid-react/chat/chat-workspace.d.ts +0 -91
- package/dist/components/data/ag-grid-react/chat/chat-workspace.js +0 -555
- package/dist/components/data/ag-grid-react/chat/chat.types.d.ts +0 -319
- package/dist/components/data/ag-grid-react/chat/index.d.ts +0 -6
- package/dist/components/data/ag-grid-react/chat/index.js +0 -24
- package/dist/components/data/ag-grid-react/chat.story-data.d.ts +0 -34
- package/dist/components/data/ag-grid-react/chat.story-sources.d.ts +0 -4
- package/dist/components/data/ag-grid-react/comments/assets/comments-no-results.png.js +0 -4
- package/dist/components/data/ag-grid-react/comments/comment-mode-toggle.d.ts +0 -6
- package/dist/components/data/ag-grid-react/comments/comment-mode-toggle.js +0 -29
- package/dist/components/data/ag-grid-react/comments/comments-actions-menu.d.ts +0 -8
- package/dist/components/data/ag-grid-react/comments/comments-actions-menu.js +0 -18
- package/dist/components/data/ag-grid-react/comments/comments-ag-grid-presence.d.ts +0 -18
- package/dist/components/data/ag-grid-react/comments/comments-ag-grid-presence.js +0 -16
- package/dist/components/data/ag-grid-react/comments/comments-capabilities.d.ts +0 -11
- package/dist/components/data/ag-grid-react/comments/comments-capabilities.js +0 -26
- package/dist/components/data/ag-grid-react/comments/comments-constants.d.ts +0 -12
- package/dist/components/data/ag-grid-react/comments/comments-constants.js +0 -21
- package/dist/components/data/ag-grid-react/comments/comments-format.d.ts +0 -20
- package/dist/components/data/ag-grid-react/comments/comments-format.js +0 -49
- package/dist/components/data/ag-grid-react/comments/comments-generation.d.ts +0 -14
- package/dist/components/data/ag-grid-react/comments/comments-generation.js +0 -18
- package/dist/components/data/ag-grid-react/comments/comments-host.d.ts +0 -10
- package/dist/components/data/ag-grid-react/comments/comments-host.js +0 -343
- package/dist/components/data/ag-grid-react/comments/comments-host.types.d.ts +0 -18
- package/dist/components/data/ag-grid-react/comments/comments-identity.d.ts +0 -7
- package/dist/components/data/ag-grid-react/comments/comments-identity.js +0 -20
- package/dist/components/data/ag-grid-react/comments/comments-menu.d.ts +0 -29
- package/dist/components/data/ag-grid-react/comments/comments-menu.js +0 -35
- package/dist/components/data/ag-grid-react/comments/comments-overlay-anchor.d.ts +0 -22
- package/dist/components/data/ag-grid-react/comments/comments-overlay-anchor.js +0 -98
- package/dist/components/data/ag-grid-react/comments/comments-overlay.d.ts +0 -21
- package/dist/components/data/ag-grid-react/comments/comments-overlay.js +0 -406
- package/dist/components/data/ag-grid-react/comments/comments-panel.d.ts +0 -9
- package/dist/components/data/ag-grid-react/comments/comments-panel.js +0 -272
- package/dist/components/data/ag-grid-react/comments/comments-persist.d.ts +0 -11
- package/dist/components/data/ag-grid-react/comments/comments-persist.js +0 -19
- package/dist/components/data/ag-grid-react/comments/comments-reveal.d.ts +0 -11
- package/dist/components/data/ag-grid-react/comments/comments-reveal.js +0 -31
- package/dist/components/data/ag-grid-react/comments/comments-ui-actions.d.ts +0 -18
- package/dist/components/data/ag-grid-react/comments/comments-ui-actions.js +0 -22
- package/dist/components/data/ag-grid-react/comments/comments-window.d.ts +0 -10
- package/dist/components/data/ag-grid-react/comments/comments-window.js +0 -62
- package/dist/components/data/ag-grid-react/comments/comments.types.d.ts +0 -178
- package/dist/components/data/ag-grid-react/comments/index.d.ts +0 -5
- package/dist/components/data/ag-grid-react/comments/index.js +0 -15
- package/dist/components/data/ag-grid-react/comments-cell-renderers-showcase.d.ts +0 -25
- package/dist/components/data/ag-grid-react/comments.story-data.d.ts +0 -37
- package/dist/components/data/ag-grid-react/comments.story-sources.d.ts +0 -11
- package/dist/components/data/ag-grid-react/grid-cell-address.d.ts +0 -21
- package/dist/components/data/ag-grid-react/grid-cell-address.js +0 -21
- package/dist/components/data/ag-grid-react/grid-row-reveal.d.ts +0 -34
- package/dist/components/data/ag-grid-react/grid-row-reveal.js +0 -33
- package/dist/components/data/ag-grid-react/notes/index.d.ts +0 -2
- package/dist/components/data/ag-grid-react/notes/index.js +0 -1
- package/dist/components/data/ag-grid-react/notes/notes-ag-grid-adapter.d.ts +0 -25
- package/dist/components/data/ag-grid-react/notes/notes-ag-grid-adapter.js +0 -32
- package/dist/components/data/ag-grid-react/notes/notes-constants.d.ts +0 -2
- package/dist/components/data/ag-grid-react/notes/notes-constants.js +0 -4
- package/dist/components/data/ag-grid-react/notes/notes.types.d.ts +0 -12
- package/dist/components/data/ag-grid-react/notes.story-sources.d.ts +0 -7
- package/dist/components/data/ag-grid-react/nova-system-column.d.ts +0 -7
- package/dist/components/data/ag-grid-react/nova-system-column.js +0 -18
- package/dist/components/forms/date-picker/use-picker-i18n.d.ts +0 -6
- package/dist/components/forms/date-picker/use-picker-i18n.js +0 -11
- package/dist/components/ui/local-raster-icons/message3d.webp.js +0 -4
- package/dist/i18n/format/collator.d.ts +0 -1
- package/dist/i18n/format/collator.js +0 -7
- package/dist/i18n/format/date-pattern.d.ts +0 -5
- package/dist/i18n/format/date-pattern.js +0 -20
- package/dist/i18n/format/format-date.d.ts +0 -9
- package/dist/i18n/format/format-date.js +0 -56
- package/dist/i18n/format/format-number.d.ts +0 -20
- package/dist/i18n/format/format-number.js +0 -68
- package/dist/i18n/format/formatter-cache.d.ts +0 -9
- package/dist/i18n/format/formatter-cache.js +0 -66
- package/dist/i18n/format/index.d.ts +0 -6
- package/dist/i18n/format/parse-number.d.ts +0 -6
- package/dist/i18n/format/parse-number.js +0 -53
- package/dist/i18n/locale-config.d.ts +0 -28
- package/dist/i18n/locale-config.js +0 -32
- package/dist/i18n/week-start.d.ts +0 -6
- package/dist/i18n/week-start.js +0 -30
- package/dist/llms/rules/data-table-chat.js +0 -1
- package/dist/llms/rules/data-table-comments.js +0 -1
- package/dist/llms/rules/data-table-notes.js +0 -1
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
function
|
|
1
|
+
function c(t) {
|
|
2
2
|
return {
|
|
3
3
|
...t,
|
|
4
|
-
title:
|
|
5
|
-
body:
|
|
6
|
-
|
|
4
|
+
title: o(t.title),
|
|
5
|
+
body: o(t.body),
|
|
6
|
+
badge: d(t.badge),
|
|
7
|
+
footer: t.footer ? o(t.footer) : void 0,
|
|
7
8
|
media: t.media ? {
|
|
8
9
|
...t.media,
|
|
9
10
|
src: l(t.media.src)
|
|
10
11
|
} : void 0,
|
|
11
12
|
actions: t.actions?.map((i) => ({
|
|
12
13
|
...i,
|
|
13
|
-
label:
|
|
14
|
+
label: o(i.label)
|
|
14
15
|
}))
|
|
15
16
|
};
|
|
16
17
|
}
|
|
@@ -19,17 +20,23 @@ function p(t) {
|
|
|
19
20
|
...t,
|
|
20
21
|
steps: t.steps.map((i) => ({
|
|
21
22
|
...i,
|
|
22
|
-
content:
|
|
23
|
+
content: c(i.content)
|
|
23
24
|
})),
|
|
24
25
|
locale: Object.fromEntries(
|
|
25
26
|
Object.entries(t.locale).map(([i, n]) => [
|
|
26
27
|
i,
|
|
27
|
-
n.map((
|
|
28
|
+
n.map((e) => c(e))
|
|
28
29
|
])
|
|
29
30
|
)
|
|
30
31
|
};
|
|
31
32
|
}
|
|
32
|
-
function
|
|
33
|
+
function d(t) {
|
|
34
|
+
if (!t)
|
|
35
|
+
return;
|
|
36
|
+
const i = o(t);
|
|
37
|
+
return i.length > 0 ? i : void 0;
|
|
38
|
+
}
|
|
39
|
+
function o(t) {
|
|
33
40
|
return t.replace(/<[^>]*>/g, "").replace(/javascript:/gi, "").trim();
|
|
34
41
|
}
|
|
35
42
|
function l(t) {
|
|
@@ -44,18 +51,18 @@ function l(t) {
|
|
|
44
51
|
}
|
|
45
52
|
return "";
|
|
46
53
|
}
|
|
47
|
-
function
|
|
54
|
+
function h(t) {
|
|
48
55
|
const i = [];
|
|
49
56
|
t.schemaVersion !== 1 && i.push(`Unsupported schemaVersion: ${t.schemaVersion}`), t.id || i.push("Guide manifest requires id"), t.steps.length || i.push("Guide manifest requires at least one step");
|
|
50
57
|
const n = /* @__PURE__ */ new Set();
|
|
51
|
-
for (const
|
|
52
|
-
n.has(
|
|
58
|
+
for (const e of t.steps)
|
|
59
|
+
n.has(e.id) && i.push(`Duplicate step id: ${e.id}`), n.add(e.id), (e.content.body.includes("<script") || e.content.body.includes("javascript:")) && i.push(`Step ${e.id} body contains disallowed content`);
|
|
53
60
|
if (t.transitions?.length) {
|
|
54
|
-
const
|
|
55
|
-
|
|
61
|
+
const e = f(t);
|
|
62
|
+
e && i.push(e);
|
|
56
63
|
}
|
|
57
|
-
for (const
|
|
58
|
-
const s = u(
|
|
64
|
+
for (const e of t.triggers) {
|
|
65
|
+
const s = u(e);
|
|
59
66
|
s && i.push(s);
|
|
60
67
|
}
|
|
61
68
|
return i;
|
|
@@ -73,30 +80,30 @@ function u(t) {
|
|
|
73
80
|
}
|
|
74
81
|
return t.plugin ? null : "Trigger plugin key is required";
|
|
75
82
|
}
|
|
76
|
-
function
|
|
83
|
+
function f(t) {
|
|
77
84
|
const i = /* @__PURE__ */ new Map();
|
|
78
|
-
for (const
|
|
79
|
-
const
|
|
80
|
-
|
|
85
|
+
for (const r of t.transitions ?? []) {
|
|
86
|
+
const a = i.get(r.from) ?? [];
|
|
87
|
+
a.push(r.to), i.set(r.from, a);
|
|
81
88
|
}
|
|
82
|
-
const n = /* @__PURE__ */ new Set(),
|
|
83
|
-
if (n.has(
|
|
89
|
+
const n = /* @__PURE__ */ new Set(), e = /* @__PURE__ */ new Set(), s = (r) => {
|
|
90
|
+
if (n.has(r))
|
|
84
91
|
return !0;
|
|
85
|
-
if (
|
|
92
|
+
if (e.has(r))
|
|
86
93
|
return !1;
|
|
87
|
-
n.add(
|
|
88
|
-
for (const
|
|
89
|
-
if (s(
|
|
94
|
+
n.add(r);
|
|
95
|
+
for (const a of i.get(r) ?? [])
|
|
96
|
+
if (s(a))
|
|
90
97
|
return !0;
|
|
91
|
-
return n.delete(
|
|
98
|
+
return n.delete(r), e.add(r), !1;
|
|
92
99
|
};
|
|
93
|
-
for (const
|
|
94
|
-
if (s(
|
|
100
|
+
for (const r of t.steps)
|
|
101
|
+
if (s(r.id))
|
|
95
102
|
return "Guide transitions contain a cycle";
|
|
96
103
|
return null;
|
|
97
104
|
}
|
|
98
105
|
export {
|
|
99
106
|
p as sanitizeGuideManifest,
|
|
100
|
-
|
|
101
|
-
|
|
107
|
+
c as sanitizeStepContent,
|
|
108
|
+
h as validateGuideManifest
|
|
102
109
|
};
|
|
@@ -9,5 +9,5 @@ export declare class TargetResolver {
|
|
|
9
9
|
resolve(descriptor: TargetDescriptor, scopeRoot?: HTMLElement | null, adapterType?: string, adapterConfig?: Record<string, unknown>): ResolvedTarget | null;
|
|
10
10
|
}
|
|
11
11
|
export declare function resolveTargetSynchronously(resolver: TargetResolver, descriptor: TargetDescriptor): ResolvedTarget | null;
|
|
12
|
-
export declare function waitForTargetResolved(resolver: TargetResolver, descriptor: TargetDescriptor, timeoutMs?: number): Promise<ResolvedTarget | null>;
|
|
12
|
+
export declare function waitForTargetResolved(resolver: TargetResolver, descriptor: TargetDescriptor, timeoutMs?: number, isCancelled?: () => boolean): Promise<ResolvedTarget | null>;
|
|
13
13
|
export declare function waitForTargetVisible(element: HTMLElement, timeoutMs?: number): Promise<boolean>;
|
|
@@ -10,18 +10,18 @@ class f {
|
|
|
10
10
|
unregisterAdapter(e) {
|
|
11
11
|
this.adapterPlugins.delete(e);
|
|
12
12
|
}
|
|
13
|
-
resolve(e, t,
|
|
14
|
-
if (
|
|
15
|
-
const
|
|
16
|
-
if (
|
|
13
|
+
resolve(e, t, s, n) {
|
|
14
|
+
if (s) {
|
|
15
|
+
const i = this.adapterPlugins.get(s);
|
|
16
|
+
if (i?.resolve) {
|
|
17
17
|
const o = {
|
|
18
18
|
targetDescriptor: e,
|
|
19
19
|
scopeRoot: t
|
|
20
20
|
};
|
|
21
21
|
try {
|
|
22
|
-
const l =
|
|
22
|
+
const l = i.resolve(
|
|
23
23
|
o,
|
|
24
|
-
|
|
24
|
+
n ?? {}
|
|
25
25
|
);
|
|
26
26
|
if (l && !(l instanceof Promise))
|
|
27
27
|
return l;
|
|
@@ -33,48 +33,50 @@ class f {
|
|
|
33
33
|
return this.refRegistry.resolveDescriptor(e, t);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
const
|
|
37
|
-
function
|
|
38
|
-
const e =
|
|
36
|
+
const u = 16;
|
|
37
|
+
function c(r) {
|
|
38
|
+
const e = r.getBoundingClientRect();
|
|
39
39
|
return e.width > 0 && e.height > 0;
|
|
40
40
|
}
|
|
41
|
-
function d(
|
|
42
|
-
const t =
|
|
43
|
-
return !t?.element || e.waitUntil === "visible" && !
|
|
41
|
+
function d(r, e) {
|
|
42
|
+
const t = r.resolve(e);
|
|
43
|
+
return !t?.element || e.waitUntil === "visible" && !c(t.element) ? null : t;
|
|
44
44
|
}
|
|
45
|
-
async function w(
|
|
45
|
+
async function w(r, e, t = 5e3, s) {
|
|
46
46
|
const n = Date.now();
|
|
47
47
|
for (; Date.now() - n < t; ) {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
if (s?.())
|
|
49
|
+
return null;
|
|
50
|
+
const i = r.resolve(e);
|
|
51
|
+
if (i?.element)
|
|
50
52
|
if (e.waitUntil === "visible") {
|
|
51
|
-
const
|
|
53
|
+
const o = t - (Date.now() - n);
|
|
52
54
|
if (await g(
|
|
53
|
-
|
|
54
|
-
Math.max(
|
|
55
|
+
i.element,
|
|
56
|
+
Math.max(o, u)
|
|
55
57
|
))
|
|
56
|
-
return
|
|
58
|
+
return i;
|
|
57
59
|
} else
|
|
58
|
-
return
|
|
59
|
-
await new Promise((
|
|
60
|
-
window.setTimeout(
|
|
60
|
+
return i;
|
|
61
|
+
await new Promise((o) => {
|
|
62
|
+
window.setTimeout(o, u);
|
|
61
63
|
});
|
|
62
64
|
}
|
|
63
65
|
return null;
|
|
64
66
|
}
|
|
65
|
-
function g(
|
|
67
|
+
function g(r, e = 5e3) {
|
|
66
68
|
if (typeof window > "u" || typeof IntersectionObserver > "u")
|
|
67
69
|
return Promise.resolve(!0);
|
|
68
|
-
const t =
|
|
69
|
-
return t.width > 0 && t.height > 0 ? Promise.resolve(!0) : new Promise((
|
|
70
|
-
const
|
|
70
|
+
const t = r.getBoundingClientRect();
|
|
71
|
+
return t.width > 0 && t.height > 0 ? Promise.resolve(!0) : new Promise((s) => {
|
|
72
|
+
const n = new IntersectionObserver((o) => {
|
|
71
73
|
o.some(
|
|
72
74
|
(a) => a.isIntersecting && a.intersectionRatio > 0
|
|
73
|
-
) && (
|
|
74
|
-
}),
|
|
75
|
-
|
|
75
|
+
) && (n.disconnect(), clearTimeout(i), s(!0));
|
|
76
|
+
}), i = setTimeout(() => {
|
|
77
|
+
n.disconnect(), s(!1);
|
|
76
78
|
}, e);
|
|
77
|
-
|
|
79
|
+
n.observe(r);
|
|
78
80
|
});
|
|
79
81
|
}
|
|
80
82
|
export {
|
|
@@ -18,9 +18,30 @@ export interface StepAction {
|
|
|
18
18
|
action: 'next' | 'skip' | 'dismiss' | 'custom';
|
|
19
19
|
customEvent?: string;
|
|
20
20
|
}
|
|
21
|
+
/** Matches command-palette `KeyBinding` (kept local to avoid a hard package coupling). */
|
|
22
|
+
export interface GuidanceKeyBinding {
|
|
23
|
+
key: string;
|
|
24
|
+
meta?: boolean;
|
|
25
|
+
ctrl?: boolean;
|
|
26
|
+
alt?: boolean;
|
|
27
|
+
shift?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface GuidanceShortcutReference {
|
|
30
|
+
label: string;
|
|
31
|
+
keybinding: GuidanceKeyBinding;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Value for `data-guidance-modal-behavior` on guidance modal surfaces.
|
|
35
|
+
* Host apps read this attribute to decide whether global shortcuts stay enabled.
|
|
36
|
+
*/
|
|
37
|
+
export type GuidanceModalBehavior = 'permit-host-shortcuts';
|
|
38
|
+
/** Announcement renderer footer layout. Defaults to `navigation` when omitted. */
|
|
39
|
+
export type GuidanceInteractionFooter = 'navigation' | 'keybinding';
|
|
21
40
|
export interface StepContent {
|
|
22
41
|
title: string;
|
|
23
42
|
body: string;
|
|
43
|
+
/** Optional eyebrow label. Hidden when empty. */
|
|
44
|
+
badge?: string;
|
|
24
45
|
media?: {
|
|
25
46
|
type: MediaType;
|
|
26
47
|
src: string;
|
|
@@ -28,12 +49,17 @@ export interface StepContent {
|
|
|
28
49
|
};
|
|
29
50
|
actions?: StepAction[];
|
|
30
51
|
footer?: string;
|
|
52
|
+
/** Primary shortcut for this step (rendered as Kbd chips when the footer uses it). */
|
|
53
|
+
keybinding?: GuidanceKeyBinding;
|
|
54
|
+
/** Optional shortcut cheat sheet rows below the body. */
|
|
55
|
+
shortcutReferences?: GuidanceShortcutReference[];
|
|
31
56
|
}
|
|
32
57
|
export interface TargetDescriptor {
|
|
33
58
|
targetId: string;
|
|
34
59
|
waitUntil?: 'mounted' | 'visible';
|
|
35
60
|
scope?: string;
|
|
36
61
|
}
|
|
62
|
+
export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right' | 'auto';
|
|
37
63
|
export interface Step {
|
|
38
64
|
id: string;
|
|
39
65
|
target?: TargetDescriptor;
|
|
@@ -42,6 +68,14 @@ export interface Step {
|
|
|
42
68
|
advanceOn: AdvanceCondition;
|
|
43
69
|
skippable: boolean;
|
|
44
70
|
timeout?: number;
|
|
71
|
+
/** Explicit popover placement relative to the target. Defaults to 'auto' (computed based on available space). */
|
|
72
|
+
placement?: PopoverPlacement;
|
|
73
|
+
/**
|
|
74
|
+
* When the step renders a modal, exposed as `data-guidance-modal-behavior` for host shortcut gating.
|
|
75
|
+
*/
|
|
76
|
+
modalBehavior?: GuidanceModalBehavior;
|
|
77
|
+
/** Announcement renderer: `keybinding` shows shortcut hint footer instead of Next/Done. */
|
|
78
|
+
interactionFooter?: GuidanceInteractionFooter;
|
|
45
79
|
}
|
|
46
80
|
export interface StepTransition {
|
|
47
81
|
from: string;
|
|
@@ -123,6 +157,12 @@ export interface RenderInstruction {
|
|
|
123
157
|
target: ResolvedTarget | null;
|
|
124
158
|
skippable: boolean;
|
|
125
159
|
advanceOn: AdvanceCondition;
|
|
160
|
+
/** True only when the previous step was an explanation and the page did not change. */
|
|
161
|
+
canGoBack: boolean;
|
|
162
|
+
/** Explicit popover placement relative to the target. Defaults to 'auto'. */
|
|
163
|
+
placement: PopoverPlacement;
|
|
164
|
+
modalBehavior?: GuidanceModalBehavior;
|
|
165
|
+
interactionFooter?: GuidanceInteractionFooter;
|
|
126
166
|
}
|
|
127
167
|
export interface TriggerContext {
|
|
128
168
|
routePath: string;
|
|
@@ -149,6 +189,7 @@ export interface RendererProps {
|
|
|
149
189
|
onNext: () => void;
|
|
150
190
|
onSkip: () => void;
|
|
151
191
|
onDismiss: () => void;
|
|
192
|
+
onBack?: () => void;
|
|
152
193
|
}
|
|
153
194
|
export interface GuidanceStorageAdapter {
|
|
154
195
|
get(keys: string[]): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FNV-1a 128-bit hash implemented as two independent 64-bit halves.
|
|
3
|
+
* Produces a 32-char hex string deterministically from a stream of string tokens.
|
|
4
|
+
*
|
|
5
|
+
* Used for column-tree fingerprints where O(N) CPU is acceptable but multi-MB
|
|
6
|
+
* string allocations are not. The 128-bit width makes collision probability
|
|
7
|
+
* negligible (~1 in 2^128) while keeping output fixed at 32 bytes.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Fnv1a128Hasher {
|
|
10
|
+
private high;
|
|
11
|
+
private low;
|
|
12
|
+
update(input: string): this;
|
|
13
|
+
digest(): string;
|
|
14
|
+
reset(): this;
|
|
15
|
+
}
|
|
16
|
+
export declare function fnv1a128(input: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const s = BigInt("0x6c62272e07bb0142"), n = BigInt("0x62b821756295c58d"), o = BigInt("0x0000000001000000"), r = BigInt("0x000000000000013b"), f = BigInt("0xffffffffffffffff");
|
|
2
|
+
class g {
|
|
3
|
+
high = s;
|
|
4
|
+
low = n;
|
|
5
|
+
update(h) {
|
|
6
|
+
for (let t = 0; t < h.length; t++) {
|
|
7
|
+
const i = BigInt(h.charCodeAt(t) & 255);
|
|
8
|
+
this.high = (this.high ^ i) * o & f, this.low = (this.low ^ i) * r & f;
|
|
9
|
+
}
|
|
10
|
+
return this;
|
|
11
|
+
}
|
|
12
|
+
digest() {
|
|
13
|
+
return this.high.toString(16).padStart(16, "0") + this.low.toString(16).padStart(16, "0");
|
|
14
|
+
}
|
|
15
|
+
reset() {
|
|
16
|
+
return this.high = s, this.low = n, this;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
g as Fnv1a128Hasher
|
|
21
|
+
};
|
package/dist/llms/index.js
CHANGED
|
@@ -6,10 +6,7 @@ import rule_4 from './rules/troubleshooting.js';
|
|
|
6
6
|
import rule_5 from './rules/accessibility.js';
|
|
7
7
|
import rule_6 from './rules/command-palette.js';
|
|
8
8
|
import rule_7 from './rules/real-world-patterns.js';
|
|
9
|
-
import rule_8 from './rules/
|
|
10
|
-
import rule_9 from './rules/data-table-notes.js';
|
|
11
|
-
import rule_10 from './rules/data-table-chat.js';
|
|
12
|
-
import rule_11 from './rules/migration.js';
|
|
9
|
+
import rule_8 from './rules/migration.js';
|
|
13
10
|
const rules = [
|
|
14
11
|
{
|
|
15
12
|
name: "impact-nova-overview",
|
|
@@ -67,31 +64,10 @@ const rules = [
|
|
|
67
64
|
alwaysApply: false,
|
|
68
65
|
globs: ["**/*chart*","**/*Chart*","**/highcharts*","**/*Chart*.tsx"],
|
|
69
66
|
},
|
|
70
|
-
{
|
|
71
|
-
name: "data-table-comments",
|
|
72
|
-
description: "Impact Nova: DataTable cell comments",
|
|
73
|
-
rule: rule_8,
|
|
74
|
-
alwaysApply: false,
|
|
75
|
-
globs: ["**/*data-table*","**/*DataTable*","**/*comment*","**/ag-grid-react/comments/**"],
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: "data-table-notes",
|
|
79
|
-
description: "Impact Nova: DataTable cell notes",
|
|
80
|
-
rule: rule_9,
|
|
81
|
-
alwaysApply: false,
|
|
82
|
-
globs: ["**/*data-table*","**/*DataTable*","**/*notes*","**/ag-grid-react/notes/**"],
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
name: "data-table-chat",
|
|
86
|
-
description: "Impact Nova: DataTable row Chat",
|
|
87
|
-
rule: rule_10,
|
|
88
|
-
alwaysApply: false,
|
|
89
|
-
globs: ["**/*data-table*","**/*DataTable*","**/*chat*","**/ag-grid-react/chat/**"],
|
|
90
|
-
},
|
|
91
67
|
{
|
|
92
68
|
name: "migration-impact-ui",
|
|
93
69
|
description: "Impact Nova: migrate from Impact UI",
|
|
94
|
-
rule:
|
|
70
|
+
rule: rule_8,
|
|
95
71
|
alwaysApply: false,
|
|
96
72
|
globs: ["**/migration/**/*","**/*migration*"],
|
|
97
73
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default "# AG Grid & Data Table — Mandatory Rules\n\n**When working with DataTable, or any data table that uses AG Grid (including Impact Nova's grid components), the following rules are mandatory. Do not deviate.**\n\n---\n\n## 1. Use AG Grid documentation only\n\n- **Refer only to AG Grid's official documentation** for grid behavior, APIs, column definitions, filtering, sorting, and all grid features.\n- Do not rely on third-party tutorials or generic \"data grid\" patterns that contradict or bypass AG Grid's docs.\n- Official docs: [ag-grid.com/documentation](https://www.ag-grid.com/documentation/) (React: [AG Grid React](https://www.ag-grid.com/react-data-grid/)).\n\n---\n\n## 2. Follow AG Grid recommended patterns\n\n- **Always follow AG Grid's recommended patterns** for:\n - Column definitions (`ColDef`, `ColGroupDef`)\n - Cell renderers and editors\n - Filtering, sorting, and row selection\n - API ref access (`gridRef.current?.api`)\n - Theming and styling (AG Grid theme / CSS variables)\n- Do not invent custom patterns that bypass or replace AG Grid's intended usage.\n\n---\n\n## 3. Use the AG Grid API only\n\n- **Rely on the AG Grid API only** for all grid operations:\n - Getting/setting data, refreshing cells, updating columns\n - Export (CSV/Excel if using Enterprise)\n - Filter/sort state, row selection, pinned columns\n - Any behavior that AG Grid exposes via its API\n- Do not manipulate the DOM or internal structure of the grid directly. Do not use non-API workarounds unless AG Grid docs explicitly suggest them.\n\n---\n\n## 4. Collaboration with ag-mcp (when installed)\n\n- **If the user has installed the ag-mcp server** (AG Grid MCP), this MCP can collaborate with it:\n - Use **ag-mcp** for AG Grid–specific questions: API reference, column config, React integration, and official examples.\n - Use **impact-nova-mcp** for Impact Nova wrappers (`DataTable`, `DataTableContent`, `processBackendColumnDefs`, `BackendColDef`, cell renderers from `impact-nova/ag-grid-react/cell-renderers`).\n - When generating or editing grid code: prefer fetching AG Grid details from ag-mcp when available, and combine with Impact Nova's DataTable/column/cell-renderer patterns from this MCP.\n- If ag-mcp is not installed, still follow rules 1–3 using AG Grid's official documentation only.\n\n---\n\n**Summary:** For any code or design involving AG Grid or Impact Nova's DataTable (which uses AG Grid), use **only** AG Grid documentation, **only** AG Grid recommended patterns, and **only** the AG Grid API—with no deviation. When ag-mcp is available, use it to get accurate AG Grid API and docs; use this MCP for Impact Nova–specific integration.\n\n---\n\n## 5. Mandatory Data Table component usage\n\n**CRITICAL RULE:** If you see a table in a screenshot, or if the user asks for a table by default, you **MUST** use **Impact Nova DataTable** from `impact-nova/data-table`. **Do not build a raw AG Grid or HTML table.**\n\n```tsx\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n useDataTable,\n} from 'impact-nova/data-table';\n```\n\nA typical Default Data Table in Impact Nova features this exact structure:\n\n```tsx\nconst DataTableWithFilters = () => {\n const { tStory } = useStorybookStoryI18n();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"columns\");\n const [showFilterStrip, setShowFilterStrip] = useState(false);\n\n return (\n <div className=\"h-[800px] w-full p-8 bg-slate-50 flex flex-col items-center justify-center\">\n <div className=\"w-full max-w-[1200px] h-[600px] bg-white rounded-lg overflow-hidden flex flex-col [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.12)]\">\n <DataTable className=\"h-full\">\n <DataTableToolbar className=\"border-b border-[#e6e8f0]\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"font-bold text-sm text-slate-800\">Sales Report</h2>\n </div>\n \n <div className=\"flex items-center gap-2\">\n <Button \n variant=\"secondary\" \n size=\"icon\" \n onClick={() => setShowFilterStrip(!showFilterStrip)}\n aria-label={showFilterStrip ? tStory('filterStrip.hideFilters') : tStory('filterStrip.showFilters')}\n >\n {showFilterStrip ? <FunnelHide size=\"xs\" /> : <FunnelShow size=\"xs\" />}\n </Button>\n\n <div className=\"h-4 w-[1px] bg-[#e6e8f0] mx-1\" />\n\n {/* Scoped Sheet for Settings - Renders inside this relative container */}\n <DataTableSheet open={sheetOpen} onOpenChange={setSheetOpen}>\n <DropdownMenu>\n <DataTableViewMenuTrigger />\n <DataTableViewMenuContent>\n <DataTableViewMenuSettingsItem />\n <DataTableViewMenuDensity />\n </DataTableViewMenuContent>\n </DropdownMenu>\n \n <DataTableSheetContent>\n <DataTableSheetHeader title=\"Table Settings\" />\n <Tabs value={activeTab} onValueChange={setActiveTab} variant=\"line\" hideInactiveLabel tooltipClassName=\"z-[110]\" className=\"flex-1 flex flex-col min-h-0 w-full px-4\">\n <TabsList>\n <TabsTrigger \n value=\"columns\" \n icon={<Column size={16} />}\n >\n Columns\n </TabsTrigger>\n <TabsTrigger \n value=\"format\" \n icon={<Font size={16} />}\n >\n Format\n </TabsTrigger>\n <TabsTrigger \n value=\"custom-filters\" \n icon={<Filter size={16} />}\n >\n Filters\n </TabsTrigger>\n </TabsList>\n \n <TabsContent value=\"columns\" className=\"flex-1 min-h-0 relative p-0 data-[state=inactive]:hidden mt-0\">\n <div className=\"flex-1 h-full p-2\">\n <DataTableColumnList />\n </div>\n </TabsContent>\n <TabsContent value=\"format\" className=\"flex-1 min-h-0 relative p-4 pt-1 data-[state=inactive]:hidden overflow-y-auto mt-0\">\n <DataTableFormatOptions />\n </TabsContent>\n <TabsContent value=\"custom-filters\" className=\"flex-1 min-h-0 relative p-4 pt-1 data-[state=inactive]:hidden overflow-y-auto mt-0\">\n <div className=\"flex flex-col gap-4 text-sm text-[#60697d]\">\n <p>Custom filter configuration would go here.</p>\n <Button variant=\"outline\" className=\"w-full justify-start\">\n + Add Condition\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n </DataTableSheetContent>\n </DataTableSheet>\n </div>\n </DataTableToolbar>\n \n <DataTableContent\n rowData={rowData}\n columnDefs={columnDefs}\n // Standard AG Grid props work here\n pagination={true}\n paginationPageSize={20}\n />\n </DataTable>\n </div>\n <p className=\"mt-4 text-slate-400 text-sm\">\n Note: The settings panel opens *inside* the table container, respecting its boundaries.\n </p>\n </div>\n );\n};\n```\nNote: This component (`DataTable`) internally uses `ag-grid-react` as a customized version. Rely on it rather than naked AG Grid.\n\n---\n\n## 6. Built-in Clipboard Handlers for JSON Objects\n\n**All DataTable and AG Grid instances in Impact Nova automatically support copying and pasting JSON objects.**\n\nThe `AgGridWrapper` component includes built-in clipboard handlers that:\n- **When copying**: Automatically stringify object values to JSON format\n- **When pasting**: Automatically parse JSON strings back to objects\n\n### How it works\n\n```tsx\n// When you copy a cell with an object value like:\n{ \n wp: { value: 6479, _isDisabled: true, cellMetadata: {...} },\n iaf: { value: 6090, _isDisabled: true, cellMetadata: {...} }\n}\n\n// It's automatically converted and split into separate Excel columns:\n// Column 1 Column 2\n// WP: 6479 IAF: 6090\n\n// Technical metadata (_isDisabled, cellMetadata) is hidden for clarity\n// Only the meaningful \"value\" is shown - perfect for PMs and non-technical users\n// Tab-separated format automatically expands into multiple columns in Excel\n```\n\n**Example with simple properties:**\n```tsx\n// Copy this object:\n{ name: \"John\", age: 30, status: \"active\" }\n\n// Expands into 3 Excel columns:\n// Column 1 Column 2 Column 3\n// name: John age: 30 status: active\n```\n\n**When pasting:**\n```tsx\n// You can paste JSON strings and they'll be parsed back to objects:\n'{\"name\":\"Jane\",\"age\":25}' → { name: \"Jane\", age: 25 }\n```\n\n**Benefits:**\n- ✅ Simple and readable for non-technical users (PMs, stakeholders)\n- ✅ Extracts only meaningful values, hides technical metadata\n- ✅ Automatically expands object properties into separate Excel columns\n- ✅ Perfect for analysis - each property gets its own column\n- ✅ Works seamlessly for both single-cell and multi-cell copy operations\n- ✅ Still supports pasting JSON back for developers\n\n### Usage\n\n**No configuration needed!** This works automatically for all DataTable instances:\n\n```tsx\n<DataTable>\n <DataTableContent\n rowData={data}\n columnDefs={columns}\n // Clipboard handlers are already active ✅\n />\n</DataTable>\n```\n\n### Override if needed\n\nYou can override the default behavior by passing your own handlers:\n\n```tsx\n<DataTableContent\n rowData={data}\n columnDefs={columns}\n processCellForClipboard={(params) => {\n // Custom copy logic\n return customFormat(params.value);\n }}\n processCellFromClipboard={(params) => {\n // Custom paste logic\n return customParse(params.value);\n }}\n/>\n```\n\n**Key benefits:**\n- ✅ Works automatically for all tables\n- ✅ No code duplication needed\n- ✅ Handles complex object structures\n- ✅ Gracefully falls back to string if JSON parsing fails\n- ✅ Can be overridden when custom behavior is needed\n\n---\n\n## 6. Column autosize on container resize\n\n**AgGridWrapper** (from `impact-nova/ag-grid-react`) automatically re-runs `autoSizeStrategy` when the grid container width changes (accordion expand, viewport resize, responsive layout).\n\n- Pass `autoSizeStrategy` to DataTable/AgGridWrapper props (e.g. `{ type: 'fitCellContents', scaleUpToFitGridWidth: true }`).\n- **Do not** add app-level ResizeObserver hacks or deferred grid mount delays — the framework handles this.\n- When applying saved column views, wait for `firstDataRendered` or `newColumnsLoaded` grid events before applying column state — not `setTimeout(0)`.\n- Strip `width`/`flex` from saved column state when applying structural views so autosize can recalculate correctly.\n\n---\n\n## 6b. Truncated text in custom cell renderers\n\n**Do not** use `OverflowTooltip` inside AG Grid cells. Use the grid-native tooltip API via **`useAgGridTruncationTooltip`** from `impact-nova/ag-grid-react`:\n\n```tsx\nimport { useAgGridTruncationTooltip } from 'impact-nova/ag-grid-react';\n\nconst MyCellRenderer = (params: ICellRendererParams) => {\n const textRef = useRef<HTMLSpanElement>(null);\n const displayValue = String(params.value ?? '');\n\n useAgGridTruncationTooltip(\n params.setTooltip,\n displayValue,\n textRef,\n 'ellipsis',\n 'cell',\n );\n\n return (\n <span ref={textRef} className=\"truncate\">\n {displayValue}\n </span>\n );\n};\n```\n\n- Pass AG Grid's `setTooltip` callback (from `ICellRendererParams` / header APIs).\n- Apply `truncate` (or `line-clamp`) on the measured element.\n- `location` is `'cell' | 'leaf' | 'group'` — affects tooltip show mode wiring.\n- For general (non-grid) truncated labels, use `OverflowTooltip` from `impact-nova/tooltip` instead.\n\n---\n\n## 7. AG Grid v36 version pin (mandatory)\n\nImpact Nova **2.2.0+** targets **AG Grid v36**. Consumer apps must install all three packages at the **exact same version**:\n\n```bash\nnpm install ag-grid-community@36.0.1 ag-grid-react@36.0.1 ag-grid-enterprise@36.0.1\n```\n\n**Rules:**\n\n- Pin `36.0.1` in `package.json` — do not float `^36` across community/react/enterprise.\n- Vite/webpack: `resolve.dedupe: ['ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react']` (see `create-impact-nova` template).\n- **Do not** import legacy AG Grid CSS theme files (`ag-grid.css`, `ag-theme-*`). Impact Nova `AgGridWrapper` applies the v36 Quartz theme (`themeQuartz.withPart(iconSetMaterial)`) via the `theme` prop.\n- Column settings (`DataTableColumnList`) sync pin/sort/filter from the live `GridApi` — do not mirror column state in app-level React state.\n\n**Column settings sheet pattern (scroll-safe — use compound layout components):**\n\n```tsx\n<DataTableSheet open={sheetOpen} onOpenChange={setSheetOpen}>\n <DataTableSheetContent>\n <DataTableSheetHeader title=\"Table Settings\" />\n <DataTableSheetBody>\n <DataTableSheetSection>{savedViews}</DataTableSheetSection>\n <DataTableSheetTabs value={tab} onValueChange={setTab} variant=\"line\" className=\"px-4\">\n <DataTableSheetTabsList>\n <TabsTrigger value=\"columns\">Columns</TabsTrigger>\n <TabsTrigger value=\"format\">Format</TabsTrigger>\n </DataTableSheetTabsList>\n <DataTableSheetTabPanel layout=\"list\" value=\"columns\" className=\"p-0 pt-2\">\n <DataTableColumnList />\n </DataTableSheetTabPanel>\n <DataTableSheetTabPanel layout=\"scroll\" value=\"format\" className=\"p-4 pt-1\">\n <DataTableFormatOptions />\n </DataTableSheetTabPanel>\n </DataTableSheetTabs>\n </DataTableSheetBody>\n </DataTableSheetContent>\n</DataTableSheet>\n```\n\nDo **not** use raw `Tabs` + manual `overflow-y-auto` in sheet bodies — see `impact-nova://data-table-sheet-layout`.\n\nStorybook reference: `Data Display/DataTable/Sheet layout` (`CanonicalComposition`) and `Column settings scenarios` (`PinSortSearchAndReset`).\n\n---\n\n## Cell Comments / Notes / Row Chat (independent opt-ins)\n\nThree **separate** `DataTableContent` props. Omit a prop → zero host, listeners, or fetch for that feature.\n\n| Feature | Identity | Import | Full guide |\n|---------|----------|--------|------------|\n| **Comments** | cell `{ rowId, colId }` | `impact-nova/ag-grid-react/comments` | `impact-nova://data-table-comments` |\n| **Notes** | cell `{ rowId, colId }` | `impact-nova/ag-grid-react/notes` | `impact-nova://data-table-notes` |\n| **Chat** | row `{ getRowId }` | `impact-nova/ag-grid-react/chat` | `impact-nova://data-table-chat` |\n\nDo **not** use AG Grid Notes for comment threads. Do **not** put threads or conversations in `rowData`. Do **not** key by DOM, `rowIndex`, or page number. Do **not** call private AG Grid beans (`INotesService`, `CellCtrl`, `showNote`).\n\nSame cell may have Comment + Note: blue triangle = Comment (`--iv-comment-indicator-color` / `--color-primary`); yellow = Note (`--iv-note-indicator-color` / `--color-warning`); split = both. Notes owns hover/click unless comment-mode; Comment still via menu / panel / comment-mode.\n\n---\n\n## Cell Comments (opt-in)\n\nUse `comments` on `DataTableContent` and helpers from `impact-nova/ag-grid-react/comments`.\n\nThis is a Google Sheets–style **cell comment thread** (create → reply → resolve → reopen). It is not Notes and has no read/unread state.\n\n**Start here:** Storybook `Data Display/DataTable/Comments/QuickStart`. **Implement from:** `impact-nova://data-table-comments`.\n\n### Identity\n\n`getRowId` + stable `colId` → `{ rowId, colId }`. Default thread id is `rowId + \"\\\\0\" + colId`. Overlay is one React tree per grid, lazy-loaded when `comments` is set.\n\n### Required config\n\n`hasIndicator` (O(1), unresolved only), `loadThread`, `persist`, `getAuthor`. Optional: `getSummaries` (list sheet), `locateRow` (row not in current model), `getCapabilities`, `commentMode` / `CommentModeToggle`, `messageActions` / `renderAvatar` (open overlay only).\n\n### Grid page vs thread page vs list page\n\nAG Grid pagination/SSRM is which **rows** are loaded. `loadThread` `request` is which **messages** are loaded. `getSummaries` is which **thread cards** are in the sheet. These are independent.\n\n### Off-page cells\n\nA comment exists even when the cell is not rendered. The triangle is a projection on painted cells only (`.iv-has-cell-comment` via `cellClassRules`).\n\n- CSRM + AG Grid `pagination`: Nova uses live `getRowNode(rowId)` then `paginationGoToPage`. No `locateRow`.\n- SSRM / app-replaced `rowData`: implement `locateRow` to load that page, then return `{ status: \"ready\" }`. Filtered-out rows (`rowIndex == null`) stay **Not in current view**.\n\n### UI\n\n- Right-click a cell → **Add comment**. When Notes are off, native AG Grid note items are stripped. When Notes are on, native note actions stay.\n- Do not pass `notesDataSource` for Comments — use `notes={...}` for AG Grid Notes.\n\n---\n\n## Cell Notes (opt-in)\n\nUse `notes` on `DataTableContent` and types from `impact-nova/ag-grid-react/notes`.\n\nThis is public AG Grid 36 `NotesModule` + `notesDataSource` (cell text + native popup). It is not a Comment thread.\n\n**Start here:** Storybook `Data Display/DataTable/Notes/QuickStart`. **Implement from:** `impact-nova://data-table-notes`.\n\n`getNote` / `setNote` keyed by `{ rowId, colId }`. Omit `notes` for zero Notes runtime. The popup shell is AG Grid’s `.ag-notes-popup` — do not replace it with a React slot.\n\n---\n\n## Row Chat (opt-in)\n\nUse `chat` on `DataTableContent` and helpers from `impact-nova/ag-grid-react/chat`.\n\nChat is **row-scoped**: many conversations per `getRowId`. It is not a cell comment and not an AG Grid Note.\n\n**Start here:** Storybook `Data Display/DataTable/Chat/QuickStart`. **Implement from:** `impact-nova://data-table-chat`.\n\n### Required config\n\n`hasConversation` (O(1) presence), `loadConversation` (newest window + `before` cursor), `persist` (one event, not the lifetime array), `getAuthor`. Optional: `unreadCount`, `getSummaries`, `locateRow` (required for app-paged / SSRM), `column: false`, `can(action, context)`, `listPeople`, `renderComposer` / `renderAvatar` / `renderMessageBody`.\n\n### System column\n\nDefault injects pinned-right `iv-chat` (69px). Excluded from the column tree, saved views, auto-size, and export. Do not persist it in consumer column state. Cell renderer is a vanilla `ICellRendererComp` — not per-row React.\n\n### Pagination\n\n- Client pagination: all rows stay in the model. Do not pass `locateRow`.\n- Server / app-paged: pass `locateRow(rowId)` and load the page. Filtered rows (`rowIndex == null`) open Chat with **Hidden by current filter** — Nova does not call `locateRow`.\n\n### Permissions and composition\n\nPass `can(action, context)` with `ChatAction = view | create | edit | delete | invite | remove-member`. Do not explode booleans (`canAddMember`). Leave / admin / transfer-ownership are **not** Chat domain — use `listActions`.\n\nChat is a DataTable config + `render*` slots — **not** a Radix `<Chat><ChatHeader/></Chat>` tree. Map vendor DTOs in `loadConversation` / `listPeople` / `persist`. Do not add a WebSocket layer inside Nova.\n\n---\n\n";
|
|
1
|
+
export default "# AG Grid & Data Table — Mandatory Rules\n\n**When working with DataTable, or any data table that uses AG Grid (including Impact Nova's grid components), the following rules are mandatory. Do not deviate.**\n\n---\n\n## 1. Use AG Grid documentation only\n\n- **Refer only to AG Grid's official documentation** for grid behavior, APIs, column definitions, filtering, sorting, and all grid features.\n- Do not rely on third-party tutorials or generic \"data grid\" patterns that contradict or bypass AG Grid's docs.\n- Official docs: [ag-grid.com/documentation](https://www.ag-grid.com/documentation/) (React: [AG Grid React](https://www.ag-grid.com/react-data-grid/)).\n\n---\n\n## 2. Follow AG Grid recommended patterns\n\n- **Always follow AG Grid's recommended patterns** for:\n - Column definitions (`ColDef`, `ColGroupDef`)\n - Cell renderers and editors\n - Filtering, sorting, and row selection\n - API ref access (`gridRef.current?.api`)\n - Theming and styling (AG Grid theme / CSS variables)\n- Do not invent custom patterns that bypass or replace AG Grid's intended usage.\n\n---\n\n## 3. Use the AG Grid API only\n\n- **Rely on the AG Grid API only** for all grid operations:\n - Getting/setting data, refreshing cells, updating columns\n - Export (CSV/Excel if using Enterprise)\n - Filter/sort state, row selection, pinned columns\n - Any behavior that AG Grid exposes via its API\n- Do not manipulate the DOM or internal structure of the grid directly. Do not use non-API workarounds unless AG Grid docs explicitly suggest them.\n\n---\n\n## 4. Collaboration with ag-mcp (when installed)\n\n- **If the user has installed the ag-mcp server** (AG Grid MCP), this MCP can collaborate with it:\n - Use **ag-mcp** for AG Grid–specific questions: API reference, column config, React integration, and official examples.\n - Use **impact-nova-mcp** for Impact Nova wrappers (`DataTable`, `DataTableContent`, `processBackendColumnDefs`, `BackendColDef`, cell renderers from `impact-nova/ag-grid-react/cell-renderers`).\n - When generating or editing grid code: prefer fetching AG Grid details from ag-mcp when available, and combine with Impact Nova's DataTable/column/cell-renderer patterns from this MCP.\n- If ag-mcp is not installed, still follow rules 1–3 using AG Grid's official documentation only.\n\n---\n\n**Summary:** For any code or design involving AG Grid or Impact Nova's DataTable (which uses AG Grid), use **only** AG Grid documentation, **only** AG Grid recommended patterns, and **only** the AG Grid API—with no deviation. When ag-mcp is available, use it to get accurate AG Grid API and docs; use this MCP for Impact Nova–specific integration.\n\n---\n\n## 5. Mandatory Data Table component usage\n\n**CRITICAL RULE:** If you see a table in a screenshot, or if the user asks for a table by default, you **MUST** use **Impact Nova DataTable** from `impact-nova/data-table`. **Do not build a raw AG Grid or HTML table.**\n\n```tsx\nimport {\n DataTable,\n DataTableContent,\n DataTableToolbar,\n useDataTable,\n} from 'impact-nova/data-table';\n```\n\nA typical Default Data Table in Impact Nova features this exact structure:\n\n```tsx\nconst DataTableWithFilters = () => {\n const { tStory } = useStorybookStoryI18n();\n const [sheetOpen, setSheetOpen] = useState(false);\n const [activeTab, setActiveTab] = useState(\"columns\");\n const [showFilterStrip, setShowFilterStrip] = useState(false);\n\n return (\n <div className=\"h-[800px] w-full p-8 bg-slate-50 flex flex-col items-center justify-center\">\n <div className=\"w-full max-w-[1200px] h-[600px] bg-white rounded-lg overflow-hidden flex flex-col [box-shadow:0px_0px_4px_0px_rgba(0,0,0,0.12)]\">\n <DataTable className=\"h-full\">\n <DataTableToolbar className=\"border-b border-[#e6e8f0]\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"font-bold text-sm text-slate-800\">Sales Report</h2>\n </div>\n \n <div className=\"flex items-center gap-2\">\n <Button \n variant=\"secondary\" \n size=\"icon\" \n onClick={() => setShowFilterStrip(!showFilterStrip)}\n aria-label={showFilterStrip ? tStory('filterStrip.hideFilters') : tStory('filterStrip.showFilters')}\n >\n {showFilterStrip ? <FunnelHide size=\"xs\" /> : <FunnelShow size=\"xs\" />}\n </Button>\n\n <div className=\"h-4 w-[1px] bg-[#e6e8f0] mx-1\" />\n\n {/* Scoped Sheet for Settings - Renders inside this relative container */}\n <DataTableSheet open={sheetOpen} onOpenChange={setSheetOpen}>\n <DropdownMenu>\n <DataTableViewMenuTrigger />\n <DataTableViewMenuContent>\n <DataTableViewMenuSettingsItem />\n <DataTableViewMenuDensity />\n </DataTableViewMenuContent>\n </DropdownMenu>\n \n <DataTableSheetContent>\n <DataTableSheetHeader title=\"Table Settings\" />\n <Tabs value={activeTab} onValueChange={setActiveTab} variant=\"line\" hideInactiveLabel tooltipClassName=\"z-[110]\" className=\"flex-1 flex flex-col min-h-0 w-full px-4\">\n <TabsList>\n <TabsTrigger \n value=\"columns\" \n icon={<Column size={16} />}\n >\n Columns\n </TabsTrigger>\n <TabsTrigger \n value=\"format\" \n icon={<Font size={16} />}\n >\n Format\n </TabsTrigger>\n <TabsTrigger \n value=\"custom-filters\" \n icon={<Filter size={16} />}\n >\n Filters\n </TabsTrigger>\n </TabsList>\n \n <TabsContent value=\"columns\" className=\"flex-1 min-h-0 relative p-0 data-[state=inactive]:hidden mt-0\">\n <div className=\"flex-1 h-full p-2\">\n <DataTableColumnList />\n </div>\n </TabsContent>\n <TabsContent value=\"format\" className=\"flex-1 min-h-0 relative p-4 pt-1 data-[state=inactive]:hidden overflow-y-auto mt-0\">\n <DataTableFormatOptions />\n </TabsContent>\n <TabsContent value=\"custom-filters\" className=\"flex-1 min-h-0 relative p-4 pt-1 data-[state=inactive]:hidden overflow-y-auto mt-0\">\n <div className=\"flex flex-col gap-4 text-sm text-[#60697d]\">\n <p>Custom filter configuration would go here.</p>\n <Button variant=\"outline\" className=\"w-full justify-start\">\n + Add Condition\n </Button>\n </div>\n </TabsContent>\n </Tabs>\n </DataTableSheetContent>\n </DataTableSheet>\n </div>\n </DataTableToolbar>\n \n <DataTableContent\n rowData={rowData}\n columnDefs={columnDefs}\n // Standard AG Grid props work here\n pagination={true}\n paginationPageSize={20}\n />\n </DataTable>\n </div>\n <p className=\"mt-4 text-slate-400 text-sm\">\n Note: The settings panel opens *inside* the table container, respecting its boundaries.\n </p>\n </div>\n );\n};\n```\nNote: This component (`DataTable`) internally uses `ag-grid-react` as a customized version. Rely on it rather than naked AG Grid.\n\n---\n\n## 6. Built-in Clipboard Handlers for JSON Objects\n\n**All DataTable and AG Grid instances in Impact Nova automatically support copying and pasting JSON objects.**\n\nThe `AgGridWrapper` component includes built-in clipboard handlers that:\n- **When copying**: Automatically stringify object values to JSON format\n- **When pasting**: Automatically parse JSON strings back to objects\n\n### How it works\n\n```tsx\n// When you copy a cell with an object value like:\n{ \n wp: { value: 6479, _isDisabled: true, cellMetadata: {...} },\n iaf: { value: 6090, _isDisabled: true, cellMetadata: {...} }\n}\n\n// It's automatically converted and split into separate Excel columns:\n// Column 1 Column 2\n// WP: 6479 IAF: 6090\n\n// Technical metadata (_isDisabled, cellMetadata) is hidden for clarity\n// Only the meaningful \"value\" is shown - perfect for PMs and non-technical users\n// Tab-separated format automatically expands into multiple columns in Excel\n```\n\n**Example with simple properties:**\n```tsx\n// Copy this object:\n{ name: \"John\", age: 30, status: \"active\" }\n\n// Expands into 3 Excel columns:\n// Column 1 Column 2 Column 3\n// name: John age: 30 status: active\n```\n\n**When pasting:**\n```tsx\n// You can paste JSON strings and they'll be parsed back to objects:\n'{\"name\":\"Jane\",\"age\":25}' → { name: \"Jane\", age: 25 }\n```\n\n**Benefits:**\n- ✅ Simple and readable for non-technical users (PMs, stakeholders)\n- ✅ Extracts only meaningful values, hides technical metadata\n- ✅ Automatically expands object properties into separate Excel columns\n- ✅ Perfect for analysis - each property gets its own column\n- ✅ Works seamlessly for both single-cell and multi-cell copy operations\n- ✅ Still supports pasting JSON back for developers\n\n### Usage\n\n**No configuration needed!** This works automatically for all DataTable instances:\n\n```tsx\n<DataTable>\n <DataTableContent\n rowData={data}\n columnDefs={columns}\n // Clipboard handlers are already active ✅\n />\n</DataTable>\n```\n\n### Override if needed\n\nYou can override the default behavior by passing your own handlers:\n\n```tsx\n<DataTableContent\n rowData={data}\n columnDefs={columns}\n processCellForClipboard={(params) => {\n // Custom copy logic\n return customFormat(params.value);\n }}\n processCellFromClipboard={(params) => {\n // Custom paste logic\n return customParse(params.value);\n }}\n/>\n```\n\n**Key benefits:**\n- ✅ Works automatically for all tables\n- ✅ No code duplication needed\n- ✅ Handles complex object structures\n- ✅ Gracefully falls back to string if JSON parsing fails\n- ✅ Can be overridden when custom behavior is needed\n\n---\n\n## 6. Column autosize on container resize\n\n**AgGridWrapper** (from `impact-nova/ag-grid-react`) automatically re-runs `autoSizeStrategy` when the grid container width changes (accordion expand, viewport resize, responsive layout).\n\n- Pass `autoSizeStrategy` to DataTable/AgGridWrapper props (e.g. `{ type: 'fitCellContents', scaleUpToFitGridWidth: true }`).\n- **Do not** add app-level ResizeObserver hacks or deferred grid mount delays — the framework handles this.\n- When applying saved column views, wait for `firstDataRendered` or `newColumnsLoaded` grid events before applying column state — not `setTimeout(0)`.\n- Strip `width`/`flex` from saved column state when applying structural views so autosize can recalculate correctly.\n\n---\n\n## 6b. Truncated text in custom cell renderers\n\n**Do not** use `OverflowTooltip` inside AG Grid cells. Use the grid-native tooltip API via **`useAgGridTruncationTooltip`** from `impact-nova/ag-grid-react`:\n\n```tsx\nimport { useAgGridTruncationTooltip } from 'impact-nova/ag-grid-react';\n\nconst MyCellRenderer = (params: ICellRendererParams) => {\n const textRef = useRef<HTMLSpanElement>(null);\n const displayValue = String(params.value ?? '');\n\n useAgGridTruncationTooltip(\n params.setTooltip,\n displayValue,\n textRef,\n 'ellipsis',\n 'cell',\n );\n\n return (\n <span ref={textRef} className=\"truncate\">\n {displayValue}\n </span>\n );\n};\n```\n\n- Pass AG Grid's `setTooltip` callback (from `ICellRendererParams` / header APIs).\n- Apply `truncate` (or `line-clamp`) on the measured element.\n- `location` is `'cell' | 'leaf' | 'group'` — affects tooltip show mode wiring.\n- For general (non-grid) truncated labels, use `OverflowTooltip` from `impact-nova/tooltip` instead.\n\n---\n\n## 7. AG Grid v36 version pin (mandatory)\n\nImpact Nova **2.2.0+** targets **AG Grid v36**. Consumer apps must install all three packages at the **exact same version**:\n\n```bash\nnpm install ag-grid-community@36.0.1 ag-grid-react@36.0.1 ag-grid-enterprise@36.0.1\n```\n\n**Rules:**\n\n- Pin `36.0.1` in `package.json` — do not float `^36` across community/react/enterprise.\n- Vite/webpack: `resolve.dedupe: ['ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react']` (see `create-impact-nova` template).\n- **Do not** import legacy AG Grid CSS theme files (`ag-grid.css`, `ag-theme-*`). Impact Nova `AgGridWrapper` applies the v36 Quartz theme (`themeQuartz.withPart(iconSetMaterial)`) via the `theme` prop.\n- Column settings (`DataTableColumnList`) sync pin/sort/filter from the live `GridApi` — do not mirror column state in app-level React state.\n\n**Column settings sheet pattern (scroll-safe — use compound layout components):**\n\n```tsx\n<DataTableSheet open={sheetOpen} onOpenChange={setSheetOpen}>\n <DataTableSheetContent>\n <DataTableSheetHeader title=\"Table Settings\" />\n <DataTableSheetBody>\n <DataTableSheetSection>{savedViews}</DataTableSheetSection>\n <DataTableSheetTabs value={tab} onValueChange={setTab} variant=\"line\" className=\"px-4\">\n <DataTableSheetTabsList>\n <TabsTrigger value=\"columns\">Columns</TabsTrigger>\n <TabsTrigger value=\"format\">Format</TabsTrigger>\n </DataTableSheetTabsList>\n <DataTableSheetTabPanel layout=\"list\" value=\"columns\" className=\"p-0 pt-2\">\n <DataTableColumnList />\n </DataTableSheetTabPanel>\n <DataTableSheetTabPanel layout=\"scroll\" value=\"format\" className=\"p-4 pt-1\">\n <DataTableFormatOptions />\n </DataTableSheetTabPanel>\n </DataTableSheetTabs>\n </DataTableSheetBody>\n </DataTableSheetContent>\n</DataTableSheet>\n```\n\nDo **not** use raw `Tabs` + manual `overflow-y-auto` in sheet bodies — see `impact-nova://data-table-sheet-layout`.\n\nStorybook reference: `Data Display/DataTable/Sheet layout` (`CanonicalComposition`) and `Column settings scenarios` (`PinSortSearchAndReset`).\n\n### Non-savable columns (saved views)\n\nDynamic columns that must **not** be persisted in saved views (e.g. plan-period buckets) opt out on the **leaf** `ColDef` only:\n\n```tsx\n{\n colId: 'store_count.2027/01',\n field: 'store_count.2027/01',\n headerName: 'Jan 2027',\n context: { isSavable: false }, // leaf-only — do NOT set on ColGroupDef\n}\n```\n\n- Default when omitted: **savable** (`resolveColumnSavability` returns true unless `isSavable === false`).\n- `DataTableColumnList` shows a grey **Non Savable** badge on opted-out leaves and adds the legend entry when any exist.\n- Save/apply filtering logic (e.g. stripping non-savable columns on save, reconciling saved order with live schema on apply) is **consumer responsibility** — impact-nova provides `resolveColumnSavability` and the UI indicators only.\n\nStorybook reference: `Data Display/DataTable` — `NonSavableColumnIndicators`.\n\n---\n\n## 8. 50k+ Column Consumer Settings\n\nWhen building grids with **10,000+ columns** (planning grids, large attribute tables), apply these settings:\n\n### Required grid props\n\n```tsx\n<DataTableContent\n ensureDomOrder={false} // Skip DOM reordering for screen readers — critical at 10k+\n maintainColumnOrder={true} // Preserve column ordering after runtime column defs changes\n suppressColumnVirtualisation={false} // Ensure column virtualization is ON (default)\n/>\n```\n\n### Column picker (DataTableColumnList)\n\n- At 80+ visible items, `DataTableColumnList` automatically switches to **virtual-index drag mode** (pointer-based reorder with TanStack Virtual) instead of dnd-kit sortable (50k useSortable hooks + DOM nodes).\n- No consumer configuration needed — the switch is automatic.\n- Drag-and-drop, search, select-all, pin switches, apply/discard all remain functional.\n\n### Saved views and state management\n\n- **Use `applyColumnState({ state, applyOrder: true })` for restoring saved column views** — this is the AG Grid recommended pattern for partial column state application.\n- **Evaluate `gridApi.getState()` / `gridApi.setState()` for full grid snapshots** (includes sort, filter, column state, grouping) when persisting complex view configurations.\n- Keep `mergePartialOrderedColumnState` for picker-initiated partial edits (picker only modifies a subset of columns).\n- **Do not** manually diff columnDefs for saved views — AG Grid's state APIs handle runtime-calculated columns.\n\n### Column runtime state guard\n\n- After `newColumnsLoaded` events, Impact Nova's `columnRuntimeStateGuard` automatically restores hide/pin/order from the cached tree to prevent column-def refreshes from resetting user layout.\n- **Use `deferColumnRuntimeStateGuard(gridApi)`** when your app applies external state (e.g., from a backend save) — this skips the guard for that cycle and rebuilds the cache from your new live state.\n\n### Performance budget (CI ratchet)\n\n| Operation | Target at 50k |\n|-----------|---------------|\n| Hash fingerprint (3x) | < 200ms |\n| Tree build from grid | < 2s |\n| Cache resolve skip path | < 300ms |\n| Indicator patch (sort/filter badges) | < 500ms |\n| Authority build + fingerprint | < 500ms |\n| Authority reorder (splice) | < 50ms |\n| Column sheet open (collapsed groups) | < 500ms |\n| Drag frame time (virtual-index) | < 16ms |\n\n---\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default "# Impact Nova — Best Practices & Do's and Don'ts\n\n## Use Impact Nova components only\n\n**When building with Impact Nova, use the components that are present in this design system only.** The library includes a full set of UI components (forms, navigation, feedback, data display, layout, etc.). There is no need to create new custom components for standard UI—use what Impact Nova provides. Check `list_components` or the component catalog to see what's available; use `get_component` for the spec and usage of any component. Prefer composing existing Impact Nova components over building from scratch.\n\n## Do's\n\n1. **Use compound components** — Use subcomponents (e.g. `Dialog.Content`, `Card.Header`, `Select.Trigger`) for full control without prop drilling.\n2. **Use `cn()` and Tailwind token classes** — Merge classNames with the `cn()` helper; use design token classes (e.g. `bg-brand`, `text-content`, `border-stroke`) not raw hex or arbitrary values.\n3. **Use design tokens** — Prefer Tailwind theme tokens (colors, spacing, radius from the design system). No arbitrary values where a token exists.\n4. **Accessibility first** — Components are built on Radix UI; preserve aria-labels, keyboard support, and screen reader compatibility. Add `aria-label` for icon-only buttons.\n5. **i18n for user-facing strings
|
|
1
|
+
export default "# Impact Nova — Best Practices & Do's and Don'ts\n\n## Use Impact Nova components only\n\n**When building with Impact Nova, use the components that are present in this design system only.** The library includes a full set of UI components (forms, navigation, feedback, data display, layout, etc.). There is no need to create new custom components for standard UI—use what Impact Nova provides. Check `list_components` or the component catalog to see what's available; use `get_component` for the spec and usage of any component. Prefer composing existing Impact Nova components over building from scratch.\n\n## Do's\n\n1. **Use compound components** — Use subcomponents (e.g. `Dialog.Content`, `Card.Header`, `Select.Trigger`) for full control without prop drilling.\n2. **Use `cn()` and Tailwind token classes** — Merge classNames with the `cn()` helper; use design token classes (e.g. `bg-brand`, `text-content`, `border-stroke`) not raw hex or arbitrary values.\n3. **Use design tokens** — Prefer Tailwind theme tokens (colors, spacing, radius from the design system). No arbitrary values where a token exists.\n4. **Accessibility first** — Components are built on Radix UI; preserve aria-labels, keyboard support, and screen reader compatibility. Add `aria-label` for icon-only buttons.\n5. **i18n for user-facing strings** — Mount `ImpactNovaProviders` from `impact-nova/form` at app root; use `useImpactNovaI18n()` / `t()` for labels, placeholders, and button text. Override via props when needed.\n6. **File naming** — Use `kebab-case.tsx` for files (e.g. `file-upload.tsx`).\n7. **TypeScript** — Import and extend component props (e.g. `ButtonProps`) for type-safe wrappers.\n8. **Use `variant` and `size` props** — For appearance, use the component's built-in variant and size props (e.g. `Button variant=\"default\" size=\"lg\"`). Add `className` only for layout (e.g. margin, gap) or intentional overrides.\n\n## Don'ts\n\n1. **No inline styles for token-backed values** — Don't use `style={{ color: '...' }}` or inline hex for colors that exist as tokens.\n2. **Don't bypass tokens** — Avoid hardcoded spacing or colors; use Tailwind token classes.\n3. **Don't skip i18n** — For any user-facing label, placeholder, or message, use the i18n context or pass overrides via props.\n4. **Don't add unnecessary classNames for styling** — Components are already styled to the design standard. Use `variant` and `size` for appearance. Use `className` only for layout (e.g. `mt-4`, `flex gap-2`) or intentional overrides, not for duplicating built-in styles (e.g. don't add `rounded-lg` if the component already applies it).\n5. **Don't use non-token colors** — Stick to the design token palette (primary, secondary, accent, destructive, muted, etc.).\n6. **Don't create new components when Impact Nova already provides one** — The design system has the components you need. Use `list_components` / `get_component` to find and use them instead of building custom equivalents.\n7. **Error and empty states** — Use **Alert** for form or API errors; use **EmptyContainer** when there is no data to show (with optional action like \"Select filter\" or \"Add item\").\n\n## Composition over inheritance\n\nFavor composition. Compose subcomponents rather than extending or wrapping with custom styling that overrides the design system.\n\n## Imports\n\n**Prefer subpath imports** in production apps for tree-shaking (~98% smaller bundles vs full barrel). Use the barrel only for i18n bootstrapping or when importing many symbols from one area in a single file.\n\n- **Subpath (preferred)**: `import { Button } from 'impact-nova/button';`, `import { Card, CardContent } from 'impact-nova/card';`, `import { DataTable, DataTableContent, useDataTable } from 'impact-nova/data-table';`, `import { FilterPanel, FilterPanelSidebar } from 'impact-nova/filter-panel';`, `import { Combobox } from 'impact-nova/combobox';`\n- **App providers**: `import { ImpactNovaProviders } from 'impact-nova/form';` — mount once at root (i18n + TooltipProvider)\n- **Barrel (locale packs only)**: `import { de } from 'impact-nova';` — OK for locale packs; avoid barrel for UI components\n- **Icons (required peer)**: `npm install impact-nova-icons@^0.1.1` then `import { Pin, Chart } from 'impact-nova-icons';` — use `createIconResolver` from `impact-nova-icons/resolver` for dynamic lookup. Icons are **not** exported from `impact-nova`\n- **Types only**: `import type { Option } from 'impact-nova/select';`, `import type { SavedTableViewItem } from 'impact-nova/data-table';`, `import type { RowSelectionState } from 'impact-nova/virtualized';`\n- **i18n hooks**: `import { useImpactNovaI18n } from 'impact-nova/i18n';`\n- **Locale packs**: `import { de } from 'impact-nova/locale/de';` (also `es`, `hi`, `kn`)\n- **CSS (once at root)**: `import 'impact-nova/dist/impact-nova.css';` — or split layers: `impact-nova/impact-nova-tokens.scss`, `impact-nova/impact-nova-base.scss`, `impact-nova/impact-nova-components.css`\n\n**Vite consumers:** add `resolve.dedupe: ['react', 'react-dom', 'ag-grid-community', 'ag-grid-enterprise', 'ag-grid-react']` to avoid dual React/AG Grid instances. Exclude `impact-nova-icons` from `optimizeDeps` to prevent SVG asset warnings. Pre-bundle Highcharts modules in `optimizeDeps.include` if using Chart.\n\n## Truncated text tooltips (OverflowTooltip)\n\nUse **`OverflowTooltip`** from `impact-nova/tooltip` when CSS truncation (`truncate`, `line-clamp`) may clip content and you want a tooltip **only when overflow is detected**.\n\n```tsx\nimport { OverflowTooltip } from 'impact-nova/tooltip';\n\n<OverflowTooltip content={fullLabel}>\n <span className=\"truncate\">{fullLabel}</span>\n</OverflowTooltip>\n```\n\n**Rules:**\n\n1. **General UI** — `OverflowTooltip` or headless `useOverflowTooltip` (custom trigger via `setTriggerRef` + `onTriggerPointerEnter`).\n2. **AG Grid custom cell renderers** — `useAgGridTruncationTooltip` from `impact-nova/ag-grid-react` with AG Grid's `setTooltip`. Never wrap grid cell text in `OverflowTooltip`.\n3. **`focusable` defaults to `false`** — pointer-only, safe inside buttons, Select options, and comboboxes. Set `focusable` for standalone keyboard-accessible truncated labels.\n4. **Do not wrap Badge globally** — apply `OverflowTooltip` at call sites when a badge label may truncate.\n5. Measurement is **lazy** (pointerenter / focusin) — no mount-time ResizeObserver.\n\n## Horizontal scroll overflow (ScrollOverflowAffordance)\n\nFor metric rails, chip rows, or any horizontal overflow content with fade edges:\n\n```tsx\nimport { ScrollOverflowAffordance } from 'impact-nova/horizontal-scroller';\n\n<ScrollOverflowAffordance contentDependency={items}>\n <div className=\"flex gap-2\">{/* overflow children */}</div>\n</ScrollOverflowAffordance>\n```\n\nUse **`HorizontalScroller`** when you have `items[]` + `renderItem`. Use **`useHorizontalScrollOverflow`** for fully custom scroll chrome.\n\n## Calendar / week pickers\n\nWeek range, week picker, Wk gutter, dual-month join: apps should use **`WeekPicker`**, **`WeekRangePicker`**, or **`MultiWeekPicker`** from `impact-nova/date-picker`. Import `Calendar` from `impact-nova/calendar` only for custom chrome. There is no `<FiscalCalendar>` — pass `calendarKind=\"fiscal\"`.\n\n**Do not restyle selected days or the Wk gutter.** Selection language is built in:\n\n- Start/end days are `rounded-lg` brand squares. Do not flatten them when a week range crosses months.\n- Week **range** (`weekMode=\"range\"`) is one connected day block plus one vertical Wk track. Dual-month panes square **only the Wk cells** at the join (last week of the first month / first week of the next).\n- Week **multiple** keeps each week as its own pill.\n- Gutter highlight is pane-local: a clipped Gregorian week ending on the last Monday does not paint the next month’s W01.\n- Interval track tucks under the start/end buttons (Monday `pl-2` must not show accent left of the start square).\n\n```tsx\nimport { WeekRangePicker } from 'impact-nova/date-picker';\n\n<WeekRangePicker label=\"Reporting period\" value={range} onChange={setRange} />\n```\n\n## AG Grid / Data tables (mandatory)\n\n**When working with DataTable, or any data table that uses AG Grid:**\n- **CRITICAL RULE:** If you see a table in a screenshot, or if the user asks for a table by default, you **MUST** use **Impact Nova DataTable** from `impact-nova/data-table`. **Do not build a raw AG Grid or HTML table.**\n- Use **only** AG Grid's official documentation.\n- Follow **only** AG Grid recommended patterns.\n- Rely **only** on the AG Grid API for grid behavior. No deviation.\n- If the user has **ag-mcp** installed, use it for AG Grid API and docs and combine with this MCP for Impact Nova DataTable/column/cell-renderer integration. See resource `impact-nova://ag-grid-rules` for full rules and the default table structure.\n";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default "# Install and configure Impact Nova\n\nUse these steps to add Impact Nova to an existing project. Run the commands in your project root and apply the code changes to your entry file and layout.\n\n## 0. Scaffold a new app (recommended)\n\n**`create-impact-nova@^1.4.9
|
|
1
|
+
export default "# Install and configure Impact Nova\n\nUse these steps to add Impact Nova to an existing project. Run the commands in your project root and apply the code changes to your entry file and layout.\n\n## 0. Scaffold a new app (recommended)\n\n**`create-impact-nova@^1.4.9`** is on npm. Scaffold auto-detects dependency mode:\n\n| Where you run | `impact-nova` dependency |\n|---------------|--------------------------|\n| Published CLI / MCP (outside monorepo) | `impact-nova@^2.5.22` from npm (`latest` tag) |\n| Inside impact-nova monorepo | `file:` link to repo root |\n\n```bash\nnpx create-impact-nova my-dashboard\ncd my-dashboard\nnpm run dev\n```\n\nMCP: **`scaffold_impact_nova_app`** with `projectName` and optional `modules[]` from the user prompt.\n\n**Overrides:** CLI `--from-npm` · `--link-monorepo` · MCP `usePublishedPackages: true | false`\n\n```bash\nnpx create-impact-nova my-dashboard --from-npm\n```\n\nBase template is shell-only (Home + shared primitives). Feature pages come from recipes — see `create-impact-nova/recipes/README.md`.\n\n**Local link in an existing app** (manual):\n\n```bash\nnpm install impact-nova@file:../path-to-impact-nova-repo\n```\n\nRun `npm run build` in the impact-nova repo after design-system changes.\n\n## 1. Install the package and peer dependencies\n\n```bash\nnpm install impact-nova impact-nova-icons\nnpm install react@^19 react-dom@^19\n```\n\n**Required peers:** `react@^19`, `react-dom@^19`, `impact-nova-icons@^0.1.1`\n\n**Optional peers** (install when you use these features):\n\n| Package | Version | When needed |\n|---------|---------|-------------|\n| `ag-grid-community` | `36.0.1` | AG Grid types/API (pin with react + enterprise) |\n| `ag-grid-react` | `36.0.1` | DataTable / AG Grid |\n| `ag-grid-enterprise` | `36.0.1` | Enterprise grid features |\n| `highcharts` | `^12` | Chart component |\n| `highcharts-react-official` | `^3` | Chart component |\n| `highcharts-border-radius` | `^0.0.4` | Rounded chart corners |\n\nIf you use AG Grid or Highcharts in your app, also install:\n\n```bash\nnpm install ag-grid-community@36.0.1 ag-grid-react@36.0.1 ag-grid-enterprise@36.0.1\n# Optional, for charts:\nnpm install highcharts@^12 highcharts-react-official@^3 highcharts-border-radius@^0.0.4\n```\n\n## 2. Import styles in your root entry\n\nIn your app root (e.g. `main.tsx`, `App.tsx`, or `layout.tsx`), **import the CSS before your app component**:\n\n```tsx\nimport 'impact-nova/dist/impact-nova.css';\nimport App from './App';\n// ... rest of your bootstrap\n```\n\n## 3. Add Manrope font (recommended)\n\nIn your `index.html` or layout:\n\n```html\n<link href=\"https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap\" rel=\"stylesheet\" />\n```\n\nIn your global CSS or Tailwind base:\n\n```css\n@layer base {\n body {\n font-family: 'Manrope', sans-serif;\n }\n}\n```\n\n## 4. Wrap your app with providers (recommended)\n\nMount **`ImpactNovaProviders`** once at the app root. It bundles i18n (`ImpactNovaI18nProvider`) and `TooltipProvider` (required for tooltips since v2.0.8):\n\n```tsx\nimport { ImpactNovaProviders } from 'impact-nova/form';\n\nfunction Root() {\n return (\n <ImpactNovaProviders locale=\"en\">\n <App />\n </ImpactNovaProviders>\n );\n}\n```\n\nFor another locale, pass a locale pack:\n\n```tsx\nimport { ImpactNovaProviders } from 'impact-nova/form';\nimport { de } from 'impact-nova/locale/de';\n\n<ImpactNovaProviders locale=\"de\" messages={de}>\n <App />\n</ImpactNovaProviders>\n```\n\n**Barrel exception:** locale packs may use `import { de } from 'impact-nova'`. All UI components still use subpaths (see §5).\n\n## 5. Subpath imports (recommended)\n\nPrefer subpath imports in feature code for tree-shaking:\n\n```tsx\nimport { Button } from 'impact-nova/button';\nimport { Card, CardContent } from 'impact-nova/card';\nimport { DataTable, DataTableContent, useDataTable } from 'impact-nova/data-table';\nimport { CheckCircle } from 'impact-nova-icons';\n```\n\nThe barrel `import { Button } from 'impact-nova'` still works but pulls a larger module graph. **Use subpaths for all UI components**; reserve the barrel for locale packs at app root only. Use `ImpactNovaProviders` from `impact-nova/form` for app setup.\n\n## 6. Using Impact Nova with CSS or SCSS (no Tailwind)\n\nIf your app uses **plain CSS or SCSS** and does **not** use Tailwind, you can still use Impact Nova. Tailwind is optional. Impact Nova ships a single built CSS file (no SCSS source).\n\n- **Import the library CSS** in your app root (e.g. `main.tsx`, `App.tsx`):\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n **CSS split exports** (optional, for layered theming): `impact-nova/impact-nova-tokens.scss`, `impact-nova/impact-nova-base.scss`, `impact-nova/impact-nova-components.css`\n Or from your main stylesheet: `@import 'impact-nova/dist/impact-nova.css';` in your main.css or main.scss.\n- **Component styling** comes from Impact Nova's CSS. Use each component's `variant` and `size` props; no Tailwind classes are required.\n- **Your layout and spacing** stay in your CSS or SCSS (margins, padding, flexbox, grid). Use your usual class names; the design system does not require Tailwind utilities.\n- **Manrope font:** Add the font link in `index.html` and in your CSS/SCSS set `body { font-family: 'Manrope', sans-serif; }` (see section 3).\n- **Summary:** No Tailwind, no Tailwind config. Load `impact-nova.css` once; use components with their props; use your existing CSS/SCSS for the rest.\n\n## 6b. Theming in consumer apps\n\n| Surface | What ships |\n|---------|------------|\n| **npm / consumer apps** | **Impact Light** only — `import 'impact-nova/dist/impact-nova.css'` (from `src/theme/tokens/light.json`) |\n| **Storybook / dev** | 10 curated **theme presets** (Impact Dark, Midnight, Ocean, …) — preview switcher only |\n\n**Do not** copy Storybook preset JSON or `theme-presets.ts` into consumer apps. Presets are not in the published package.\n\n**Custom branding:** override CSS variables on `:root` or a scoped class (e.g. `.my-brand`). Use Storybook **Theme Builder** / **Token Catalog** to explore tokens, then export CSS/JSON for your overrides.\n\n## 7. Using Impact Nova with Webpack\n\nIf your app is built with **Webpack** (including Create React App, which uses Webpack):\n\n- **CSS import:** Webpack will bundle the library CSS as long as you have a rule for `.css`. Ensure your config includes something like:\n ```js\n module: {\n rules: [\n {\n test: /\\.css$/,\n use: ['style-loader', 'css-loader'],\n // or with MiniCssExtractPlugin:\n // use: [MiniCssExtractPlugin.loader, 'css-loader'],\n },\n // ... other rules (e.g. for .tsx, .js)\n ],\n },\n ```\n Then in your root component or entry:\n ```tsx\n import 'impact-nova/dist/impact-nova.css';\n ```\n- **Create React App (CRA):** No extra config. Add `import 'impact-nova/dist/impact-nova.css';` in `index.tsx` or `App.tsx`.\n- **Dedupe React / AG Grid:** If you see “multiple copies of React” or AG Grid issues, use Webpack’s `resolve.alias` so the app uses a single version:\n ```js\n resolve: {\n alias: {\n react: path.resolve(__dirname, 'node_modules/react'),\n 'react-dom': path.resolve(__dirname, 'node_modules/react-dom'),\n // If using AG Grid:\n 'ag-grid-react': path.resolve(__dirname, 'node_modules/ag-grid-react'),\n 'ag-grid-community': path.resolve(__dirname, 'node_modules/ag-grid-community'),\n 'ag-grid-enterprise': path.resolve(__dirname, 'node_modules/ag-grid-enterprise'),\n },\n },\n ```\n- **Tailwind + Webpack:** If you use Tailwind, add the Impact Nova preset and include the package in `content` (see section 7 below).\n\n## 8. Optional: extend Tailwind with Impact Nova preset\n\nIf your project uses Tailwind and you want the same theme (colors, radius), extend your `tailwind.config.js` with the preset from the package:\n\n```js\n// tailwind.config.js\nimport impactNovaPreset from 'impact-nova/tailwind.config.js';\n// → dist/tailwind.config.js (bundled theme; no package src/ required)\n\nexport default {\n presets: [impactNovaPreset],\n content: [\n './index.html',\n './src/**/*.{js,ts,jsx,tsx}',\n './node_modules/impact-nova/dist/**/*.js',\n ],\n // ... rest of your config\n};\n```\n\n## Summary checklist\n\n- [ ] `npm install impact-nova impact-nova-icons` (and react, react-dom; optional: ag-grid, highcharts)\n- [ ] `import 'impact-nova/dist/impact-nova.css'` in root entry (or @import in main.css/main.scss if using CSS or SCSS without Tailwind; see §6)\n- [ ] Add Manrope font link and body font-family\n- [ ] Wrap app with `<ImpactNovaProviders locale=\"en\">` from `impact-nova/form`\n- [ ] Use subpath imports in feature code (see §5)\n- [ ] (Optional) Add Tailwind preset and content path for impact-nova\n- [ ] **Webpack:** Ensure a CSS rule (style-loader + css-loader) and, if needed, resolve.alias for React/AG Grid\n\nAfter this, import components via subpaths: `import { Button } from 'impact-nova/button';`\n\n## 9. Dashboard app shell (optional)\n\nTo scaffold a full dashboard (sidebar, header, breadcrumb, filters), read resource **`impact-nova://layout`** or call `get_real_world_patterns` with `topic: \"layout\"`. Use `Layout` from `impact-nova/layout` — not `DynamicLayout` (grid/flex utility only).\n";
|