@mk-kit/ui 0.38.0 → 0.40.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mk-kit/ui",
3
- "version": "0.38.0",
3
+ "version": "0.40.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -5,6 +5,11 @@
5
5
  "description": "Adds @mk-kit/ui to an application: wires the theme stylesheet into angular.json and optionally scaffolds a provideMkI18n override block.",
6
6
  "factory": "./ng-add/index#ngAdd",
7
7
  "schema": "./ng-add/schema.json"
8
+ },
9
+ "migrate-primeng": {
10
+ "description": "Migrates a PrimeNG app to @mk-kit/ui: rewrites imports, class names and 1:1 selectors, annotates what needs a manual touch, cleans angular.json / package.json and writes a report.",
11
+ "factory": "./migrate-primeng/index#migratePrimeng",
12
+ "schema": "./migrate-primeng/schema.json"
8
13
  }
9
14
  }
10
15
  }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.migratePrimeng = migratePrimeng;
4
+ const mapping_1 = require("./mapping");
5
+ const transform_1 = require("./transform");
6
+ const SKIP_DIRS = new Set(['node_modules', 'dist', '.angular', '.git']);
7
+ function migratePrimeng(options) {
8
+ return (tree, context) => {
9
+ const root = normalize(options.path ?? 'src');
10
+ const dryRun = !!options.dryRun;
11
+ const reportPath = options.report ?? 'primeng-migration.md';
12
+ const files = [];
13
+ let scanned = 0;
14
+ tree.getDir(root).visit((path) => {
15
+ if (path.split('/').some((seg) => SKIP_DIRS.has(seg)))
16
+ return;
17
+ const isTs = path.endsWith('.ts') && !path.endsWith('.d.ts');
18
+ const isHtml = path.endsWith('.html');
19
+ if (!isTs && !isHtml)
20
+ return;
21
+ scanned++;
22
+ const source = tree.read(path)?.toString('utf8');
23
+ if (source === undefined || !/primeng|<p-[a-zA-Z]|\bp[A-Z][a-zA-Z]+\b/.test(source))
24
+ return;
25
+ const result = isTs ? (0, transform_1.transformTypeScript)(source) : (0, transform_1.transformTemplate)(source);
26
+ if (!result.findings.length && !result.changed)
27
+ return;
28
+ files.push({ path, findings: result.findings, changed: result.changed });
29
+ if (result.changed && !dryRun)
30
+ tree.overwrite(path, result.text);
31
+ });
32
+ const unmapped = files.some((f) => f.findings.some((x) => x.kind === 'unmapped'));
33
+ for (const [path, fn] of [
34
+ ['/angular.json', transform_1.transformAngularJson],
35
+ ['/package.json', (src) => (0, transform_1.transformPackageJson)(src, unmapped ? [] : mapping_1.PRIMENG_PACKAGES)],
36
+ ]) {
37
+ if (!tree.exists(path))
38
+ continue;
39
+ scanned++;
40
+ const result = fn(tree.read(path).toString('utf8'));
41
+ if (!result.findings.length)
42
+ continue;
43
+ files.push({ path, findings: result.findings, changed: result.changed });
44
+ if (result.changed && !dryRun)
45
+ tree.overwrite(path, result.text);
46
+ }
47
+ if (unmapped) {
48
+ files.push({
49
+ path: '/package.json',
50
+ changed: false,
51
+ findings: [{ rule: 'package:keep', message: 'primeng kept in package.json: some components have no mk-kit equivalent yet (see "Not available")', kind: 'manual', count: 1 }],
52
+ });
53
+ }
54
+ const report = (0, transform_1.renderReport)(files, { dryRun, scanned });
55
+ if (!dryRun) {
56
+ if (tree.exists(reportPath))
57
+ tree.overwrite(reportPath, report);
58
+ else
59
+ tree.create(reportPath, report);
60
+ }
61
+ const counts = { rewrite: 0, manual: 0, unmapped: 0 };
62
+ for (const f of files)
63
+ for (const x of f.findings)
64
+ counts[x.kind] += x.count;
65
+ context.logger.info(`migrate-primeng: ${dryRun ? 'dry run — ' : ''}${files.filter((f) => f.changed).length} file(s) ${dryRun ? 'would change' : 'changed'}; ` +
66
+ `${counts.rewrite} rewrites, ${counts.manual} manual steps, ${counts.unmapped} without an equivalent.` +
67
+ (dryRun ? '' : ` Report: ${reportPath}`));
68
+ if (dryRun)
69
+ context.logger.info('\n' + report);
70
+ return tree;
71
+ };
72
+ }
73
+ function normalize(p) {
74
+ const trimmed = p.replace(/\/+$/, '');
75
+ return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
76
+ }
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ /**
3
+ * PrimeNG → @mk-kit/ui mapping used by the `migrate-primeng` schematic.
4
+ *
5
+ * Two tables:
6
+ * - `MODULES`: what each `primeng/<x>` import path exports and which mk-kit
7
+ * class replaces each symbol (`null` = no drop-in equivalent → reported).
8
+ * - `SELECTORS`: template-level rewrites. `to` set + `exact` true means a
9
+ * mechanical rename is safe; otherwise the original markup is left alone
10
+ * and a `<!-- mk-kit: … -->` note is inserted once per file.
11
+ *
12
+ * Everything here is checked against the library's real exports/selectors
13
+ * (see projects/docs/public/api.json); keep it that way when editing.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.PRIMENG_PACKAGES = exports.DOCS_BASE = exports.SELECTORS = exports.MODULES = void 0;
17
+ const D = 'https://mk-kit.dev';
18
+ exports.MODULES = [
19
+ { path: 'button', symbols: { ButtonModule: 'MkButton', Button: 'MkButton', ButtonDirective: 'MkButton' }, docs: '/components/buttons' },
20
+ { path: 'splitbutton', symbols: { SplitButtonModule: 'MkSplitButton', SplitButton: 'MkSplitButton' }, note: 'mk-split-button takes an mk-menu via [menu] instead of [model].', docs: '/components/buttons' },
21
+ { path: 'inputtext', symbols: { InputTextModule: 'MkInput', InputText: 'MkInput' }, docs: '/components/text-inputs' },
22
+ { path: 'textarea', symbols: { TextareaModule: 'MkInput', Textarea: 'MkInput' }, docs: '/components/text-inputs' },
23
+ { path: 'inputtextarea', symbols: { InputTextareaModule: 'MkInput', InputTextarea: 'MkInput' }, docs: '/components/text-inputs' },
24
+ { path: 'inputnumber', symbols: { InputNumberModule: 'MkNumberInput', InputNumber: 'MkNumberInput' }, docs: '/components/text-inputs' },
25
+ { path: 'password', symbols: { PasswordModule: 'MkPasswordInput', Password: 'MkPasswordInput' }, docs: '/components/text-inputs' },
26
+ { path: 'inputotp', symbols: { InputOtpModule: 'MkOtp', InputOtp: 'MkOtp' }, docs: '/components/text-inputs' },
27
+ { path: 'checkbox', symbols: { CheckboxModule: 'MkCheckbox', Checkbox: 'MkCheckbox' }, docs: '/components/toggles' },
28
+ { path: 'radiobutton', symbols: { RadioButtonModule: 'MkRadioGroup', RadioButton: 'MkRadioGroup' }, note: 'mk-radio-group wraps mk-radio children; the group owns the value.', docs: '/components/toggles' },
29
+ { path: 'toggleswitch', symbols: { ToggleSwitchModule: 'MkSwitch', ToggleSwitch: 'MkSwitch' }, docs: '/components/toggles' },
30
+ { path: 'inputswitch', symbols: { InputSwitchModule: 'MkSwitch', InputSwitch: 'MkSwitch' }, docs: '/components/toggles' },
31
+ { path: 'select', symbols: { SelectModule: 'MkSelect', Select: 'MkSelect' }, note: 'mk-select takes [options] as {label, value}[] — no optionLabel/optionValue.', docs: '/components/forms' },
32
+ { path: 'dropdown', symbols: { DropdownModule: 'MkSelect', Dropdown: 'MkSelect' }, note: 'mk-select takes [options] as {label, value}[] — no optionLabel/optionValue.', docs: '/components/forms' },
33
+ { path: 'multiselect', symbols: { MultiSelectModule: 'MkMultiSelect', MultiSelect: 'MkMultiSelect' }, note: 'mk-multi-select takes [options] as {label, value}[].', docs: '/components/selection' },
34
+ { path: 'listbox', symbols: { ListboxModule: 'MkListbox', Listbox: 'MkListbox' }, docs: '/components/selection' },
35
+ { path: 'autocomplete', symbols: { AutoCompleteModule: 'MkAutocomplete', AutoComplete: 'MkAutocomplete' }, note: 'Pass [options] (sync or async) instead of (completeMethod) + [suggestions].', docs: '/components/selection' },
36
+ { path: 'cascadeselect', symbols: { CascadeSelectModule: 'MkCascader', CascadeSelect: 'MkCascader' }, docs: '/components/selection' },
37
+ { path: 'treeselect', symbols: { TreeSelectModule: 'MkTreeSelect', TreeSelect: 'MkTreeSelect' }, docs: '/components/selection' },
38
+ { path: 'selectbutton', symbols: { SelectButtonModule: 'MkButtonToggleGroup', SelectButton: 'MkButtonToggleGroup' }, note: 'mk-button-toggle-group uses mk-button-toggle children instead of [options].', docs: '/components/selection' },
39
+ { path: 'togglebutton', symbols: { ToggleButtonModule: 'MkButtonToggleGroup', ToggleButton: 'MkButtonToggleGroup' }, docs: '/components/selection' },
40
+ { path: 'datepicker', symbols: { DatePickerModule: 'MkDatePicker', DatePicker: 'MkDatePicker' }, docs: '/components/date-time' },
41
+ { path: 'calendar', symbols: { CalendarModule: 'MkDatePicker', Calendar: 'MkDatePicker' }, docs: '/components/date-time' },
42
+ { path: 'rating', symbols: { RatingModule: 'MkRating', Rating: 'MkRating' }, docs: '/components/sliders' },
43
+ { path: 'slider', symbols: { SliderModule: 'MkSlider', Slider: 'MkSlider' }, note: 'Range mode → mk-range-slider.', docs: '/components/sliders' },
44
+ { path: 'colorpicker', symbols: { ColorPickerModule: 'MkColorPicker', ColorPicker: 'MkColorPicker' }, docs: '/components/sliders' },
45
+ { path: 'fileupload', symbols: { FileUploadModule: 'MkFileUpload', FileUpload: 'MkFileUpload' }, note: 'Replace [url] + (onUpload) with [uploadFn].', docs: '/components/forms' },
46
+ { path: 'editor', symbols: { EditorModule: 'MkRichText', Editor: 'MkRichText' }, docs: '/components/rich-text' },
47
+ { path: 'knob', symbols: { KnobModule: 'MkProgressRing', Knob: 'MkProgressRing' }, note: 'mk-progress-ring is display-only; for an editable dial use mk-slider.', docs: '/components/proportion-charts' },
48
+ { path: 'table', symbols: { TableModule: 'MkTable', Table: 'MkTable' }, note: 'mk-table renders from [columns] + [data]; templates via mkTableCell. Server-side paging/sorting → MkTableDataSource.', docs: '/components/table' },
49
+ { path: 'paginator', symbols: { PaginatorModule: 'MkPagination', Paginator: 'MkPagination' }, note: 'mk-pagination is 1-based with [total] + [pageSize]; no [first]/[rows].', docs: '/components/navigation' },
50
+ { path: 'tree', symbols: { TreeModule: 'MkTree', Tree: 'MkTree' }, note: 'Node shape is {label, children, key}; use [nodes].', docs: '/components/tree' },
51
+ { path: 'treetable', symbols: { TreeTableModule: 'MkTable', TreeTable: 'MkTable' }, note: 'mk-table with [childrenKey] renders tree rows.', docs: '/components/table' },
52
+ { path: 'dataview', symbols: { DataViewModule: null, DataView: null }, note: 'No data-view: compose mk-list / mk-grid with @for.', docs: '/components/cards-lists' },
53
+ { path: 'orderlist', symbols: { OrderListModule: 'MkSortableList', OrderList: 'MkSortableList' }, docs: '/components/drag-drop' },
54
+ { path: 'picklist', symbols: { PickListModule: 'MkTransferList', PickList: 'MkTransferList' }, docs: '/components/selection' },
55
+ { path: 'scroller', symbols: { ScrollerModule: 'MkVirtualScroll', Scroller: 'MkVirtualScroll' }, docs: '/components/data' },
56
+ { path: 'virtualscroller', symbols: { VirtualScrollerModule: 'MkVirtualScroll', VirtualScroller: 'MkVirtualScroll' }, docs: '/components/data' },
57
+ { path: 'timeline', symbols: { TimelineModule: 'MkTimeline', Timeline: 'MkTimeline' }, note: 'Use mk-timeline-item children instead of [value] + templates.', docs: '/components/empty-timeline' },
58
+ { path: 'organizationchart', symbols: { OrganizationChartModule: null, OrganizationChart: null }, note: 'No org chart yet.', docs: '/components/tree' },
59
+ { path: 'chart', symbols: { ChartModule: null, UIChart: null }, note: 'p-chart wraps Chart.js. mk-kit ships SVG charts: mk-line-chart, mk-bar-chart, mk-donut-chart, mk-gauge, … — map by [type].', docs: '/components/charts' },
60
+ { path: 'dialog', symbols: { DialogModule: 'MkDialog', Dialog: 'MkDialog' }, note: 'mk-dialog is opened through MkDialogService.open(Component) — no [(visible)] toggle. Move the dialog body into its own component.', docs: '/components/dialogs' },
61
+ { path: 'dynamicdialog', symbols: { DynamicDialogModule: null, DialogService: 'MkDialogService', DynamicDialogRef: 'MkOverlayRef', DynamicDialogConfig: null }, note: 'MkDialogService.open(Cmp, { data }); inject MK_OVERLAY_DATA in the component; await ref.afterClosed.', docs: '/components/dialogs' },
62
+ { path: 'confirmdialog', symbols: { ConfirmDialogModule: null, ConfirmDialog: null }, note: 'Use MkDialogService.confirm({ title, message, tone }) — no <p-confirmDialog> host element needed.', docs: '/components/dialogs' },
63
+ { path: 'confirmpopup', symbols: { ConfirmPopupModule: 'MkPopconfirm', ConfirmPopup: 'MkPopconfirm' }, note: 'Use [mkPopconfirmFor] on the trigger.', docs: '/components/popovers' },
64
+ { path: 'toast', symbols: { ToastModule: null, Toast: null }, note: 'No <p-toast> host: inject MkToastService and call success/info/warning/danger(message, { title }).', docs: '/components/snackbar' },
65
+ { path: 'message', symbols: { MessageModule: 'MkAlert', Message: 'MkAlert' }, docs: '/components/feedback' },
66
+ { path: 'messages', symbols: { MessagesModule: 'MkAlert', Messages: 'MkAlert' }, note: 'One mk-alert per message.', docs: '/components/feedback' },
67
+ { path: 'tooltip', symbols: { TooltipModule: 'MkTooltip', Tooltip: 'MkTooltip' }, docs: '/components/popovers' },
68
+ { path: 'popover', symbols: { PopoverModule: 'MkPopover', Popover: 'MkPopover' }, note: 'Use [mkPopoverTriggerFor] on the trigger instead of #op.toggle($event).', docs: '/components/popovers' },
69
+ { path: 'overlaypanel', symbols: { OverlayPanelModule: 'MkPopover', OverlayPanel: 'MkPopover' }, note: 'Use [mkPopoverTriggerFor] on the trigger instead of #op.toggle($event).', docs: '/components/popovers' },
70
+ { path: 'drawer', symbols: { DrawerModule: 'MkDrawer', Drawer: 'MkDrawer' }, docs: '/components/drawer' },
71
+ { path: 'sidebar', symbols: { SidebarModule: 'MkDrawer', Sidebar: 'MkDrawer' }, docs: '/components/drawer' },
72
+ { path: 'blockui', symbols: { BlockUIModule: 'MkBlockUi', BlockUI: 'MkBlockUi' }, note: 'Use the [mkBlockUi] directive on the region.', docs: '/components/feedback' },
73
+ { path: 'progressbar', symbols: { ProgressBarModule: 'MkProgressBar', ProgressBar: 'MkProgressBar' }, docs: '/components/loading' },
74
+ { path: 'progressspinner', symbols: { ProgressSpinnerModule: 'MkSpinner', ProgressSpinner: 'MkSpinner' }, docs: '/components/loading' },
75
+ { path: 'skeleton', symbols: { SkeletonModule: 'MkSkeleton', Skeleton: 'MkSkeleton' }, docs: '/components/loading' },
76
+ { path: 'badge', symbols: { BadgeModule: 'MkBadge', Badge: 'MkBadge', BadgeDirective: 'MkBadge' }, note: 'pBadge attribute → <mk-badge> element next to the target.', docs: '/components/badges-avatars' },
77
+ { path: 'tag', symbols: { TagModule: 'MkTag', Tag: 'MkTag' }, docs: '/components/badges-avatars' },
78
+ { path: 'chip', symbols: { ChipModule: 'MkChip', Chip: 'MkChip' }, docs: '/components/badges-avatars' },
79
+ { path: 'avatar', symbols: { AvatarModule: 'MkAvatar', Avatar: 'MkAvatar' }, docs: '/components/badges-avatars' },
80
+ { path: 'avatargroup', symbols: { AvatarGroupModule: 'MkAvatarGroup', AvatarGroup: 'MkAvatarGroup' }, docs: '/components/badges-avatars' },
81
+ { path: 'card', symbols: { CardModule: 'MkCard', Card: 'MkCard' }, note: 'Header/footer via mk-card-header / mk-card-footer.', docs: '/components/cards-lists' },
82
+ { path: 'panel', symbols: { PanelModule: 'MkCard', Panel: 'MkCard' }, note: 'Collapsible panel → mk-accordion-item.', docs: '/components/cards-lists' },
83
+ { path: 'fieldset', symbols: { FieldsetModule: 'MkCard', Fieldset: 'MkCard' }, docs: '/components/cards-lists' },
84
+ { path: 'divider', symbols: { DividerModule: 'MkDivider', Divider: 'MkDivider' }, docs: '/components/cards-lists' },
85
+ { path: 'toolbar', symbols: { ToolbarModule: 'MkToolbar', Toolbar: 'MkToolbar' }, docs: '/components/structure' },
86
+ { path: 'splitter', symbols: { SplitterModule: 'MkSplitter', Splitter: 'MkSplitter' }, docs: '/components/structure' },
87
+ { path: 'accordion', symbols: { AccordionModule: 'MkAccordion', Accordion: 'MkAccordion', AccordionPanel: 'MkAccordionItem', AccordionHeader: 'MkAccordionHeader', AccordionContent: null, AccordionTab: 'MkAccordionItem' }, docs: '/components/navigation' },
88
+ { path: 'tabs', symbols: { TabsModule: 'MkTabs', Tabs: 'MkTabs', TabList: null, Tab: 'MkTab', TabPanels: null, TabPanel: null }, note: 'mk-tabs uses <mk-tab label="…"> children: merge each p-tab + p-tabpanel pair.', docs: '/components/navigation' },
89
+ { path: 'tabview', symbols: { TabViewModule: 'MkTabs', TabView: 'MkTabs', TabPanel: 'MkTab' }, docs: '/components/navigation' },
90
+ { path: 'stepper', symbols: { StepperModule: 'MkStepper', Stepper: 'MkStepper', StepList: null, Step: 'MkStep', StepPanels: null, StepPanel: null }, docs: '/components/stepper' },
91
+ { path: 'steps', symbols: { StepsModule: 'MkStepper', Steps: 'MkStepper' }, note: 'Use mk-step children instead of [model].', docs: '/components/stepper' },
92
+ { path: 'menu', symbols: { MenuModule: 'MkMenu', Menu: 'MkMenu' }, note: 'Use mk-menu-item children instead of [model]; open with [mkMenuTriggerFor].', docs: '/components/navigation' },
93
+ { path: 'menubar', symbols: { MenubarModule: 'MkNavList', Menubar: 'MkNavList' }, note: 'Horizontal nav → mk-nav-list / mk-toolbar with mkButton links.', docs: '/components/command-nav' },
94
+ { path: 'tieredmenu', symbols: { TieredMenuModule: 'MkMenu', TieredMenu: 'MkMenu' }, note: 'Nested items via [mkSubmenuFor].', docs: '/components/navigation' },
95
+ { path: 'contextmenu', symbols: { ContextMenuModule: 'MkContextMenuTrigger', ContextMenu: 'MkContextMenuTrigger' }, note: 'Use [mkContextMenuTriggerFor]="menu" on the element.', docs: '/components/context-menu' },
96
+ { path: 'megamenu', symbols: { MegaMenuModule: null, MegaMenu: null }, note: 'No mega menu; compose mk-popover + mk-nav-list.', docs: '/components/command-nav' },
97
+ { path: 'panelmenu', symbols: { PanelMenuModule: 'MkNavList', PanelMenu: 'MkNavList' }, note: 'mk-nav-list with mk-nav-group children.', docs: '/components/command-nav' },
98
+ { path: 'breadcrumb', symbols: { BreadcrumbModule: 'MkBreadcrumb', Breadcrumb: 'MkBreadcrumb' }, note: 'Use mk-breadcrumb-item children instead of [model].', docs: '/components/navigation' },
99
+ { path: 'dock', symbols: { DockModule: null, Dock: null }, note: 'No dock.', docs: '/components/navigation' },
100
+ { path: 'carousel', symbols: { CarouselModule: 'MkCarousel', Carousel: 'MkCarousel' }, note: 'Use mkCarouselSlide templates instead of [value].', docs: '/components/data' },
101
+ { path: 'galleria', symbols: { GalleriaModule: 'MkImageGallery', Galleria: 'MkImageGallery' }, docs: '/components/images' },
102
+ { path: 'image', symbols: { ImageModule: 'MkImage', Image: 'MkImage' }, note: 'Preview → MkLightboxService.', docs: '/components/images' },
103
+ { path: 'scrollpanel', symbols: { ScrollPanelModule: 'MkScrollArea', ScrollPanel: 'MkScrollArea' }, docs: '/components/structure' },
104
+ { path: 'scrolltop', symbols: { ScrollTopModule: 'MkBackToTop', ScrollTop: 'MkBackToTop' }, docs: '/components/navigation' },
105
+ { path: 'speeddial', symbols: { SpeedDialModule: 'MkFab', SpeedDial: 'MkFab' }, note: 'mk-fab with mkFabAction children.', docs: '/components/navigation' },
106
+ { path: 'inplace', symbols: { InplaceModule: 'MkInlineEdit', Inplace: 'MkInlineEdit' }, docs: '/components/table' },
107
+ { path: 'metergroup', symbols: { MeterGroupModule: null, MeterGroup: null }, note: 'No meter group yet; mk-progress-bar per segment.', docs: '/components/loading' },
108
+ { path: 'terminal', symbols: { TerminalModule: null, Terminal: null }, note: 'No terminal.', docs: '/components/data' },
109
+ { path: 'iconfield', symbols: { IconFieldModule: 'MkInputGroup', IconField: 'MkInputGroup', InputIcon: 'MkIcon', InputIconModule: 'MkIcon' }, note: 'mk-input-group with a prefix slot.', docs: '/components/text-inputs' },
110
+ { path: 'inputgroup', symbols: { InputGroupModule: 'MkInputGroup', InputGroup: 'MkInputGroup' }, docs: '/components/text-inputs' },
111
+ { path: 'inputgroupaddon', symbols: { InputGroupAddonModule: null, InputGroupAddon: null }, note: 'Addons are content slots of mk-input-group.', docs: '/components/text-inputs' },
112
+ { path: 'floatlabel', symbols: { FloatLabelModule: 'MkFormField', FloatLabel: 'MkFormField' }, note: 'mk-form-field labelPosition="float".', docs: '/components/forms' },
113
+ { path: 'iftalabel', symbols: { IftaLabelModule: 'MkFormField', IftaLabel: 'MkFormField' }, docs: '/components/forms' },
114
+ { path: 'keyfilter', symbols: { KeyFilterModule: 'MkMask', KeyFilter: 'MkMask' }, note: 'Use [mkMask] patterns or a Validators.pattern.', docs: '/components/utilities' },
115
+ { path: 'inputmask', symbols: { InputMaskModule: 'MkMask', InputMask: 'MkMask' }, note: '[mkMask] on a native input (tokens 0 / A / *).', docs: '/components/utilities' },
116
+ { path: 'ripple', symbols: { RippleModule: 'MkRipple', Ripple: 'MkRipple' }, docs: '/components/utilities' },
117
+ { path: 'focustrap', symbols: { FocusTrapModule: 'MkFocusTrap', FocusTrap: 'MkFocusTrap' }, docs: '/core-services' },
118
+ { path: 'autofocus', symbols: { AutoFocusModule: 'MkAutofocus', AutoFocus: 'MkAutofocus' }, docs: '/components/utilities' },
119
+ { path: 'animateonscroll', symbols: { AnimateOnScrollModule: 'MkIntersect', AnimateOnScroll: 'MkIntersect' }, docs: '/components/utilities' },
120
+ { path: 'styleclass', symbols: { StyleClassModule: null, StyleClass: null }, note: 'Bind [class.x] / @if instead.' },
121
+ { path: 'dragdrop', symbols: { DragDropModule: 'MkDropList', Draggable: 'MkDrag', Droppable: 'MkDropList' }, docs: '/components/drag-drop' },
122
+ { path: 'api', symbols: { MessageService: 'MkToastService', ConfirmationService: 'MkDialogService', MenuItem: null, PrimeNGConfig: null, PrimeIcons: null, FilterService: null, SortEvent: null, TreeNode: null, SelectItem: null, PrimeTemplate: null, SharedModule: null }, note: 'MessageService.add({severity, summary, detail}) → MkToastService.<severity>(detail, { title: summary }). ConfirmationService.confirm({…}) → await MkDialogService.confirm({ title, message, tone }).', docs: '/components/snackbar' },
123
+ { path: 'config', symbols: { PrimeNG: null, providePrimeNG: null }, note: 'providePrimeNG({ theme }) → import @mk-kit/ui/styles.css and use provideMkI18n for strings.', docs: '/theming' },
124
+ ];
125
+ /** Element / attribute rewrites for templates. Order matters only for overlapping prefixes (longest first is enforced by the transform). */
126
+ exports.SELECTORS = [
127
+ // Buttons
128
+ { kind: 'attribute', from: 'pButton', to: 'mkButton', attrs: { severity: 'tone', '[severity]': '[tone]', '[outlined]': null, '[loading]': '[loading]', '[disabled]': '[disabled]' }, note: 'label="…" / icon="…" become content: <button mkButton><mk-icon name="…" /> Label</button>; [outlined]/[text]/[link] → variant="outline" | "ghost" | "link".', manual: true, docs: '/components/buttons' },
129
+ { kind: 'element', from: 'p-button', note: '<p-button label="…"> → <button mkButton>…</button>; severity → tone; [outlined] → variant="outline".', docs: '/components/buttons' },
130
+ { kind: 'element', from: 'p-splitbutton', to: 'mk-split-button', manual: true, note: '[model] → an <mk-menu #m> with mk-menu-item children and [menu]="m"; label → content.', docs: '/components/buttons' },
131
+ { kind: 'element', from: 'p-splitButton', to: 'mk-split-button', manual: true, note: '[model] → an <mk-menu #m> with mk-menu-item children and [menu]="m"; label → content.', docs: '/components/buttons' },
132
+ // Text inputs
133
+ { kind: 'attribute', from: 'pInputText', to: 'mkInput', docs: '/components/text-inputs' },
134
+ { kind: 'attribute', from: 'pTextarea', to: 'mkInput', docs: '/components/text-inputs' },
135
+ { kind: 'attribute', from: 'pInputTextarea', to: 'mkInput', docs: '/components/text-inputs' },
136
+ { kind: 'attribute', from: 'pAutoFocus', to: 'mkAutofocus', docs: '/components/utilities' },
137
+ { kind: 'attribute', from: 'pRipple', to: 'mkRipple', docs: '/components/utilities' },
138
+ { kind: 'attribute', from: 'pTooltip', to: 'mkTooltip', attrs: { tooltipPosition: 'mkTooltipPlacement', '[tooltipPosition]': '[mkTooltipPlacement]' }, docs: '/components/popovers' },
139
+ { kind: 'attribute', from: 'pBadge', note: 'pBadge attribute → place an <mk-badge dot> / <mk-badge>{{ n }}</mk-badge> next to the element.', docs: '/components/badges-avatars' },
140
+ { kind: 'attribute', from: 'pKeyFilter', note: 'Use [mkMask] or Validators.pattern.', docs: '/components/utilities' },
141
+ { kind: 'attribute', from: 'pInputMask', to: 'mkMask', manual: true, note: 'Mask tokens: PrimeNG 9/a/* → mk-kit 0/A/*.', docs: '/components/utilities' },
142
+ { kind: 'element', from: 'p-inputnumber', to: 'mk-number-input', manual: true, note: 'mode="currency" → mk-currency-input; [showButtons] is always on.', docs: '/components/text-inputs' },
143
+ { kind: 'element', from: 'p-inputNumber', to: 'mk-number-input', manual: true, note: 'mode="currency" → mk-currency-input; [showButtons] is always on.', docs: '/components/text-inputs' },
144
+ { kind: 'element', from: 'p-password', to: 'mk-password-input', attrs: { '[feedback]': '[showStrength]', '[toggleMask]': null }, docs: '/components/text-inputs' },
145
+ { kind: 'element', from: 'p-inputotp', to: 'mk-otp', docs: '/components/text-inputs' },
146
+ { kind: 'element', from: 'p-inputOtp', to: 'mk-otp', docs: '/components/text-inputs' },
147
+ { kind: 'element', from: 'p-floatlabel', to: 'mk-form-field', manual: true, note: 'Add labelPosition="float" and move the <label> text into [label].', docs: '/components/forms' },
148
+ { kind: 'element', from: 'p-floatLabel', to: 'mk-form-field', manual: true, note: 'Add labelPosition="float" and move the <label> text into [label].', docs: '/components/forms' },
149
+ { kind: 'element', from: 'p-iconfield', to: 'mk-input-group', manual: true, note: 'Icon → a prefix slot inside mk-input-group.', docs: '/components/text-inputs' },
150
+ { kind: 'element', from: 'p-iconField', to: 'mk-input-group', manual: true, note: 'Icon → a prefix slot inside mk-input-group.', docs: '/components/text-inputs' },
151
+ { kind: 'element', from: 'p-inputgroupaddon', note: 'Addons are content slots of mk-input-group: replace the wrapper with a plain element inside mk-input-group.', docs: '/components/text-inputs' },
152
+ { kind: 'element', from: 'p-inputGroupAddon', note: 'Addons are content slots of mk-input-group: replace the wrapper with a plain element inside mk-input-group.', docs: '/components/text-inputs' },
153
+ { kind: 'element', from: 'p-inputgroup', to: 'mk-input-group', docs: '/components/text-inputs' },
154
+ { kind: 'element', from: 'p-inputGroup', to: 'mk-input-group', docs: '/components/text-inputs' },
155
+ // Toggles & selection
156
+ { kind: 'element', from: 'p-checkbox', to: 'mk-checkbox', manual: true, note: 'Non-binary (array) checkboxes → one mk-checkbox per option; label="…" → content.', docs: '/components/toggles' },
157
+ { kind: 'element', from: 'p-radiobutton', note: 'Wrap options in <mk-radio-group [(ngModel)]> with <mk-radio value="…">Label</mk-radio> children.', docs: '/components/toggles' },
158
+ { kind: 'element', from: 'p-radioButton', note: 'Wrap options in <mk-radio-group [(ngModel)]> with <mk-radio value="…">Label</mk-radio> children.', docs: '/components/toggles' },
159
+ { kind: 'element', from: 'p-toggleswitch', to: 'mk-switch', docs: '/components/toggles' },
160
+ { kind: 'element', from: 'p-toggleSwitch', to: 'mk-switch', docs: '/components/toggles' },
161
+ { kind: 'element', from: 'p-inputswitch', to: 'mk-switch', docs: '/components/toggles' },
162
+ { kind: 'element', from: 'p-inputSwitch', to: 'mk-switch', docs: '/components/toggles' },
163
+ { kind: 'element', from: 'p-select', to: 'mk-select', manual: true, note: 'Map [options] to {label, value}[] (no optionLabel/optionValue); [showClear] not needed.', docs: '/components/forms' },
164
+ { kind: 'element', from: 'p-dropdown', to: 'mk-select', manual: true, note: 'Map [options] to {label, value}[] (no optionLabel/optionValue).', docs: '/components/forms' },
165
+ { kind: 'element', from: 'p-multiselect', to: 'mk-multi-select', manual: true, note: 'Map [options] to {label, value}[].', docs: '/components/selection' },
166
+ { kind: 'element', from: 'p-multiSelect', to: 'mk-multi-select', manual: true, note: 'Map [options] to {label, value}[].', docs: '/components/selection' },
167
+ { kind: 'element', from: 'p-listbox', to: 'mk-listbox', manual: true, note: 'Map [options] to {label, value}[].', docs: '/components/selection' },
168
+ { kind: 'element', from: 'p-autocomplete', to: 'mk-autocomplete', manual: true, note: '(completeMethod) + [suggestions] → [options] (array or (query) => Promise/Observable).', docs: '/components/selection' },
169
+ { kind: 'element', from: 'p-autoComplete', to: 'mk-autocomplete', manual: true, note: '(completeMethod) + [suggestions] → [options] (array or (query) => Promise/Observable).', docs: '/components/selection' },
170
+ { kind: 'element', from: 'p-cascadeselect', to: 'mk-cascader', manual: true, note: 'Options: {label, value, children}[].', docs: '/components/selection' },
171
+ { kind: 'element', from: 'p-cascadeSelect', to: 'mk-cascader', manual: true, note: 'Options: {label, value, children}[].', docs: '/components/selection' },
172
+ { kind: 'element', from: 'p-treeselect', to: 'mk-tree-select', manual: true, note: '[options] → [nodes] ({label, key, children}).', docs: '/components/selection' },
173
+ { kind: 'element', from: 'p-treeSelect', to: 'mk-tree-select', manual: true, note: '[options] → [nodes] ({label, key, children}).', docs: '/components/selection' },
174
+ { kind: 'element', from: 'p-selectbutton', to: 'mk-button-toggle-group', manual: true, note: '[options] → <mk-button-toggle value="…">Label</mk-button-toggle> children.', docs: '/components/selection' },
175
+ { kind: 'element', from: 'p-selectButton', to: 'mk-button-toggle-group', manual: true, note: '[options] → <mk-button-toggle value="…">Label</mk-button-toggle> children.', docs: '/components/selection' },
176
+ { kind: 'element', from: 'p-togglebutton', note: 'Single toggle → <mk-button-toggle-group> with one <mk-button-toggle>, or a checkbox-style mkButton.', docs: '/components/selection' },
177
+ { kind: 'element', from: 'p-toggleButton', note: 'Single toggle → <mk-button-toggle-group> with one <mk-button-toggle>, or a checkbox-style mkButton.', docs: '/components/selection' },
178
+ { kind: 'element', from: 'p-rating', to: 'mk-rating', attrs: { stars: 'max', '[stars]': '[max]' }, docs: '/components/sliders' },
179
+ { kind: 'element', from: 'p-slider', to: 'mk-slider', manual: true, note: '[range] → mk-range-slider with [low, high] value.', docs: '/components/sliders' },
180
+ { kind: 'element', from: 'p-colorpicker', to: 'mk-color-picker', docs: '/components/sliders' },
181
+ { kind: 'element', from: 'p-colorPicker', to: 'mk-color-picker', docs: '/components/sliders' },
182
+ { kind: 'element', from: 'p-knob', note: 'Display → mk-progress-ring [value]; editable → mk-slider.', docs: '/components/proportion-charts' },
183
+ // Dates
184
+ { kind: 'element', from: 'p-datepicker', to: 'mk-date-picker', manual: true, note: '[minDate]/[maxDate] → [min]/[max]; [showTime] → mk-datetime-picker; [selectionMode]="range" → mk-date-range-picker; dateFormat → displayFormat (yyyy-MM-dd tokens).', docs: '/components/date-time' },
185
+ { kind: 'element', from: 'p-datePicker', to: 'mk-date-picker', manual: true, note: '[minDate]/[maxDate] → [min]/[max]; [showTime] → mk-datetime-picker; range → mk-date-range-picker.', docs: '/components/date-time' },
186
+ { kind: 'element', from: 'p-calendar', to: 'mk-date-picker', manual: true, note: '[minDate]/[maxDate] → [min]/[max]; [showTime] → mk-datetime-picker; range → mk-date-range-picker; [timeOnly] → mk-time-picker.', docs: '/components/date-time' },
187
+ // Files & editors
188
+ { kind: 'element', from: 'p-fileupload', to: 'mk-file-upload', manual: true, note: '[url] + (onUpload) → [uploadFn]; [maxFileSize] → [maxSize]; mode="basic" is the default look.', docs: '/components/forms' },
189
+ { kind: 'element', from: 'p-fileUpload', to: 'mk-file-upload', manual: true, note: '[url] + (onUpload) → [uploadFn]; [maxFileSize] → [maxSize].', docs: '/components/forms' },
190
+ { kind: 'element', from: 'p-editor', to: 'mk-rich-text', manual: true, note: 'HTML in/out via [(ngModel)] works; toolbar customisation differs (see docs).', docs: '/components/rich-text' },
191
+ // Data
192
+ { kind: 'element', from: 'p-table', to: 'mk-table', manual: true, note: '[value] → [data]; define [columns] ({key, header, sortable}) and drop the <ng-template pTemplate="header|body"> blocks (custom cells → mkTableCell); [paginator] → mk-pagination or MkTableDataSource; selection → [selectable] + [(selected)].', attrs: { '[value]': '[data]', '[selectionMode]': null, '[rowHover]': '[hover]', '[striped]': '[zebra]', '[stripedRows]': '[zebra]' }, docs: '/components/table' },
193
+ { kind: 'element', from: 'p-treetable', to: 'mk-table', manual: true, note: 'mk-table with [childrenKey]="\'children\'"; same column mapping as p-table.', attrs: { '[value]': '[data]' }, docs: '/components/table' },
194
+ { kind: 'element', from: 'p-treeTable', to: 'mk-table', manual: true, note: 'mk-table with [childrenKey]="\'children\'"; same column mapping as p-table.', attrs: { '[value]': '[data]' }, docs: '/components/table' },
195
+ { kind: 'element', from: 'p-paginator', to: 'mk-pagination', manual: true, note: '[rows] → [pageSize], [totalRecords] → [total], [first] → 1-based [(page)]; (onPageChange) → (pageChange).', attrs: { '[rows]': '[pageSize]', '[totalRecords]': '[total]', '(onPageChange)': '(pageChange)' }, docs: '/components/navigation' },
196
+ { kind: 'element', from: 'p-dataview', note: 'Compose mk-list / mk-grid with @for; mk-pagination for paging.', docs: '/components/cards-lists' },
197
+ { kind: 'element', from: 'p-dataView', note: 'Compose mk-list / mk-grid with @for; mk-pagination for paging.', docs: '/components/cards-lists' },
198
+ { kind: 'element', from: 'p-tree', to: 'mk-tree', manual: true, note: '[value] → [nodes] ({label, key, children}); [(selection)] → [(selected)].', attrs: { '[value]': '[nodes]' }, docs: '/components/tree' },
199
+ { kind: 'element', from: 'p-orderlist', to: 'mk-sortable-list', manual: true, note: '[value] → [(items)] with a projected row template.', docs: '/components/drag-drop' },
200
+ { kind: 'element', from: 'p-orderList', to: 'mk-sortable-list', manual: true, note: '[value] → [(items)] with a projected row template.', docs: '/components/drag-drop' },
201
+ { kind: 'element', from: 'p-picklist', to: 'mk-transfer-list', manual: true, note: '[source]/[target] → [items] + [(value)].', docs: '/components/selection' },
202
+ { kind: 'element', from: 'p-pickList', to: 'mk-transfer-list', manual: true, note: '[source]/[target] → [items] + [(value)].', docs: '/components/selection' },
203
+ { kind: 'element', from: 'p-scroller', to: 'mk-virtual-scroll', manual: true, note: '[itemSize] → [itemHeight]; row template is projected.', attrs: { '[itemSize]': '[itemHeight]' }, docs: '/components/data' },
204
+ { kind: 'element', from: 'p-virtualscroller', to: 'mk-virtual-scroll', manual: true, note: '[itemSize] → [itemHeight]; row template is projected.', attrs: { '[itemSize]': '[itemHeight]' }, docs: '/components/data' },
205
+ { kind: 'element', from: 'p-timeline', to: 'mk-timeline', manual: true, note: '[value] + templates → <mk-timeline-item> children.', docs: '/components/empty-timeline' },
206
+ { kind: 'element', from: 'p-organizationchart', note: 'No org chart yet — mk-tree is the closest.', docs: '/components/tree' },
207
+ { kind: 'element', from: 'p-organizationChart', note: 'No org chart yet — mk-tree is the closest.', docs: '/components/tree' },
208
+ { kind: 'element', from: 'p-chart', note: 'Replace by the matching SVG chart: type="line" → mk-line-chart, "bar" → mk-bar-chart, "doughnut"/"pie" → mk-donut-chart, "radar" → mk-radar-chart, "scatter"/"bubble" → mk-scatter-chart. Data shape is plain series arrays.', docs: '/components/charts' },
209
+ { kind: 'element', from: 'p-metergroup', note: 'No meter group yet; use one mk-progress-bar per segment.', docs: '/components/loading' },
210
+ { kind: 'element', from: 'p-meterGroup', note: 'No meter group yet; use one mk-progress-bar per segment.', docs: '/components/loading' },
211
+ // Overlays & feedback
212
+ { kind: 'element', from: 'p-dialog', note: 'mk-dialog is opened with MkDialogService.open(Component, { data }) — move this <p-dialog> body into a component (see docs) and drop [(visible)].', docs: '/components/dialogs' },
213
+ { kind: 'element', from: 'p-confirmdialog', note: 'Remove this host element; call await MkDialogService.confirm({ title, message, tone }) where you used ConfirmationService.', docs: '/components/dialogs' },
214
+ { kind: 'element', from: 'p-confirmDialog', note: 'Remove this host element; call await MkDialogService.confirm({ title, message, tone }) where you used ConfirmationService.', docs: '/components/dialogs' },
215
+ { kind: 'element', from: 'p-confirmpopup', note: 'Put [mkPopconfirmFor]="pc" on the trigger and an <mk-popconfirm #pc message="…" (confirm)="…"> next to it.', docs: '/components/popovers' },
216
+ { kind: 'element', from: 'p-confirmPopup', note: 'Put [mkPopconfirmFor]="pc" on the trigger and an <mk-popconfirm #pc message="…" (confirm)="…"> next to it.', docs: '/components/popovers' },
217
+ { kind: 'element', from: 'p-toast', note: 'Remove this host element; MkToastService mounts its own container. MessageService.add({severity, summary, detail}) → toast.<severity>(detail, { title: summary }).', docs: '/components/snackbar' },
218
+ { kind: 'element', from: 'p-message', to: 'mk-alert', manual: true, note: 'severity → tone (error → danger); text="…" → content.', attrs: { severity: 'tone', '[severity]': '[tone]' }, docs: '/components/feedback' },
219
+ { kind: 'element', from: 'p-messages', note: 'Render one <mk-alert [tone]> per message with @for.', docs: '/components/feedback' },
220
+ { kind: 'element', from: 'p-popover', note: 'Put [mkPopoverTriggerFor]="pop" on the trigger and rename this element to <mk-popover #pop>; drop #op.toggle($event).', docs: '/components/popovers' },
221
+ { kind: 'element', from: 'p-overlaypanel', note: 'Put [mkPopoverTriggerFor]="pop" on the trigger and rename this element to <mk-popover #pop>; drop #op.toggle($event).', docs: '/components/popovers' },
222
+ { kind: 'element', from: 'p-overlayPanel', note: 'Put [mkPopoverTriggerFor]="pop" on the trigger and rename this element to <mk-popover #pop>; drop #op.toggle($event).', docs: '/components/popovers' },
223
+ { kind: 'element', from: 'p-drawer', to: 'mk-drawer', manual: true, note: '[(visible)] → [(open)]; position → side; [modal] → [hasBackdrop].', attrs: { '[(visible)]': '[(open)]', '[visible]': '[open]', '(visibleChange)': '(openChange)', position: 'side', '[position]': '[side]', '[modal]': '[hasBackdrop]', header: 'heading', '[header]': '[heading]' }, docs: '/components/drawer' },
224
+ { kind: 'element', from: 'p-sidebar', to: 'mk-drawer', manual: true, note: '[(visible)] → [(open)]; position → side; [modal] → [hasBackdrop].', attrs: { '[(visible)]': '[(open)]', '[visible]': '[open]', '(visibleChange)': '(openChange)', position: 'side', '[position]': '[side]', '[modal]': '[hasBackdrop]', header: 'heading', '[header]': '[heading]' }, docs: '/components/drawer' },
225
+ { kind: 'element', from: 'p-blockui', note: 'Use the [mkBlockUi]="busy()" directive on the region (or MkBlockUiService for the page).', docs: '/components/feedback' },
226
+ { kind: 'element', from: 'p-blockUI', note: 'Use the [mkBlockUi]="busy()" directive on the region (or MkBlockUiService for the page).', docs: '/components/feedback' },
227
+ { kind: 'element', from: 'p-progressbar', to: 'mk-progress-bar', attrs: { '[mode]': null, mode: null }, manual: true, note: 'mode="indeterminate" → the indeterminate attribute.', docs: '/components/loading' },
228
+ { kind: 'element', from: 'p-progressBar', to: 'mk-progress-bar', manual: true, note: 'mode="indeterminate" → the indeterminate attribute.', docs: '/components/loading' },
229
+ { kind: 'element', from: 'p-progressspinner', to: 'mk-spinner', docs: '/components/loading' },
230
+ { kind: 'element', from: 'p-progressSpinner', to: 'mk-spinner', docs: '/components/loading' },
231
+ { kind: 'element', from: 'p-skeleton', to: 'mk-skeleton', attrs: { shape: 'shape', width: 'width', height: 'height' }, docs: '/components/loading' },
232
+ { kind: 'element', from: 'p-badge', to: 'mk-badge', manual: true, note: '[value] → content; severity → tone.', attrs: { severity: 'tone', '[severity]': '[tone]' }, docs: '/components/badges-avatars' },
233
+ { kind: 'element', from: 'p-tag', to: 'mk-tag', manual: true, note: '[value] → content; severity → tone; [rounded] is the default look.', attrs: { severity: 'tone', '[severity]': '[tone]' }, docs: '/components/badges-avatars' },
234
+ { kind: 'element', from: 'p-chip', to: 'mk-chip', manual: true, note: 'label="…" → content; [removable] is the same; (onRemove) → (remove).', attrs: { '(onRemove)': '(remove)' }, docs: '/components/badges-avatars' },
235
+ { kind: 'element', from: 'p-avatar', to: 'mk-avatar', manual: true, note: 'label="AB" → name="A B" (initials are derived); image → src; shape="circle" is the default.', attrs: { image: 'src', '[image]': '[src]' }, docs: '/components/badges-avatars' },
236
+ { kind: 'element', from: 'p-avatargroup', to: 'mk-avatar-group', docs: '/components/badges-avatars' },
237
+ { kind: 'element', from: 'p-avatarGroup', to: 'mk-avatar-group', docs: '/components/badges-avatars' },
238
+ { kind: 'element', from: 'p-card', to: 'mk-card', manual: true, note: 'header="…" → <mk-card-header> / <mk-card-title>; pTemplate="footer" → <mk-card-footer>.', docs: '/components/cards-lists' },
239
+ { kind: 'element', from: 'p-panel', to: 'mk-card', manual: true, note: 'header → <mk-card-header>; [toggleable] → use mk-accordion-item instead.', docs: '/components/cards-lists' },
240
+ { kind: 'element', from: 'p-fieldset', to: 'mk-card', manual: true, note: 'legend → <mk-card-header>.', docs: '/components/cards-lists' },
241
+ { kind: 'element', from: 'p-divider', to: 'mk-divider', attrs: { layout: 'orientation', '[layout]': '[orientation]' }, docs: '/components/cards-lists' },
242
+ { kind: 'element', from: 'p-toolbar', to: 'mk-toolbar', manual: true, note: 'pTemplate="start|end" → plain content; use mk-flex for alignment.', docs: '/components/structure' },
243
+ { kind: 'element', from: 'p-splitter', to: 'mk-splitter', manual: true, note: 'p-splitterpanel children → two projected children; [layout] → orientation.', attrs: { layout: 'orientation', '[layout]': '[orientation]' }, docs: '/components/structure' },
244
+ { kind: 'element', from: 'p-splitterpanel', note: 'Drop the wrapper: mk-splitter projects its two children directly.', docs: '/components/structure' },
245
+ { kind: 'element', from: 'p-splitterPanel', note: 'Drop the wrapper: mk-splitter projects its two children directly.', docs: '/components/structure' },
246
+ { kind: 'element', from: 'p-scrollpanel', to: 'mk-scroll-area', docs: '/components/structure' },
247
+ { kind: 'element', from: 'p-scrollPanel', to: 'mk-scroll-area', docs: '/components/structure' },
248
+ { kind: 'element', from: 'p-scrolltop', to: 'mk-back-to-top', docs: '/components/navigation' },
249
+ { kind: 'element', from: 'p-scrollTop', to: 'mk-back-to-top', docs: '/components/navigation' },
250
+ { kind: 'element', from: 'p-image', to: 'mk-image', manual: true, note: '[preview] → MkLightboxService.open().', docs: '/components/images' },
251
+ { kind: 'element', from: 'p-galleria', to: 'mk-image-gallery', manual: true, note: '[value] → [images] ({src, alt}).', docs: '/components/images' },
252
+ { kind: 'element', from: 'p-carousel', to: 'mk-carousel', manual: true, note: '[value] + template → <ng-template mkCarouselSlide> per item.', docs: '/components/data' },
253
+ { kind: 'element', from: 'p-inplace', to: 'mk-inline-edit', manual: true, note: 'Bind [(value)] instead of display/content templates.', docs: '/components/table' },
254
+ // Navigation
255
+ { kind: 'element', from: 'p-tabs', to: 'mk-tabs', manual: true, note: 'Merge each <p-tab> + <p-tabpanel> pair into <mk-tab label="…">…</mk-tab>; drop p-tablist / p-tabpanels.', docs: '/components/navigation' },
256
+ { kind: 'element', from: 'p-tablist', note: 'Drop: mk-tabs renders its own tab list.', docs: '/components/navigation' },
257
+ { kind: 'element', from: 'p-tabpanels', note: 'Drop: <mk-tab> children go directly inside <mk-tabs>.', docs: '/components/navigation' },
258
+ { kind: 'element', from: 'p-tabpanel', note: 'Becomes <mk-tab label="…"> (label from the matching <p-tab>).', docs: '/components/navigation' },
259
+ { kind: 'element', from: 'p-tabview', to: 'mk-tabs', manual: true, note: '[(activeIndex)] → [(selectedIndex)].', attrs: { '[(activeIndex)]': '[(selectedIndex)]', '[activeIndex]': '[selectedIndex]', '(activeIndexChange)': '(selectedIndexChange)' }, docs: '/components/navigation' },
260
+ { kind: 'element', from: 'p-tabView', to: 'mk-tabs', manual: true, note: '[(activeIndex)] → [(selectedIndex)].', attrs: { '[(activeIndex)]': '[(selectedIndex)]', '[activeIndex]': '[selectedIndex]', '(activeIndexChange)': '(selectedIndexChange)' }, docs: '/components/navigation' },
261
+ { kind: 'element', from: 'p-tabPanel', to: 'mk-tab', attrs: { header: 'label', '[header]': '[label]' }, docs: '/components/navigation' },
262
+ { kind: 'element', from: 'p-accordion', to: 'mk-accordion', attrs: { '[multiple]': '[multi]', multiple: 'multi' }, docs: '/components/navigation' },
263
+ { kind: 'element', from: 'p-accordion-panel', to: 'mk-accordion-item', manual: true, note: 'Move the <p-accordion-header> text into header="…" and drop the p-accordion-content wrapper.', docs: '/components/navigation' },
264
+ { kind: 'element', from: 'p-accordionpanel', to: 'mk-accordion-item', manual: true, note: 'Move the <p-accordion-header> text into header="…" and drop the p-accordion-content wrapper.', docs: '/components/navigation' },
265
+ { kind: 'element', from: 'p-accordion-header', note: 'Becomes header="…" on the mk-accordion-item (or an [mkAccordionHeader] template).', docs: '/components/navigation' },
266
+ { kind: 'element', from: 'p-accordion-content', note: 'Drop the wrapper: content goes directly inside mk-accordion-item.', docs: '/components/navigation' },
267
+ { kind: 'element', from: 'p-accordiontab', to: 'mk-accordion-item', docs: '/components/navigation' },
268
+ { kind: 'element', from: 'p-accordionTab', to: 'mk-accordion-item', docs: '/components/navigation' },
269
+ { kind: 'element', from: 'p-stepper', to: 'mk-stepper', manual: true, note: 'Each p-step + p-step-panel → <mk-step label="…">; [(value)] → [(selectedIndex)] (0-based).', docs: '/components/stepper' },
270
+ { kind: 'element', from: 'p-steps', to: 'mk-stepper', manual: true, note: '[model] → <mk-step label="…"> children; [(activeIndex)] → [(selectedIndex)].', attrs: { '[(activeIndex)]': '[(selectedIndex)]', '[activeIndex]': '[selectedIndex]' }, docs: '/components/stepper' },
271
+ { kind: 'element', from: 'p-menu', to: 'mk-menu', manual: true, note: '[model] → <mk-menu-item> children; [popup] + #menu.toggle($event) → [mkMenuTriggerFor]="menu" on the button.', docs: '/components/navigation' },
272
+ { kind: 'element', from: 'p-tieredmenu', to: 'mk-menu', manual: true, note: '[model] → <mk-menu-item> children; nested items via [mkSubmenuFor].', docs: '/components/navigation' },
273
+ { kind: 'element', from: 'p-tieredMenu', to: 'mk-menu', manual: true, note: '[model] → <mk-menu-item> children; nested items via [mkSubmenuFor].', docs: '/components/navigation' },
274
+ { kind: 'element', from: 'p-contextmenu', to: 'mk-menu', manual: true, note: '[model] → <mk-menu-item> children; [target] → put [mkContextMenuTriggerFor]="menu" on the element.', docs: '/components/context-menu' },
275
+ { kind: 'element', from: 'p-contextMenu', to: 'mk-menu', manual: true, note: '[model] → <mk-menu-item> children; [target] → put [mkContextMenuTriggerFor]="menu" on the element.', docs: '/components/context-menu' },
276
+ { kind: 'element', from: 'p-menubar', note: 'Horizontal nav → <mk-toolbar> with mkButton links, or mk-nav-list.', docs: '/components/command-nav' },
277
+ { kind: 'element', from: 'p-megamenu', note: 'No mega menu; compose mk-popover + mk-nav-list.', docs: '/components/command-nav' },
278
+ { kind: 'element', from: 'p-megaMenu', note: 'No mega menu; compose mk-popover + mk-nav-list.', docs: '/components/command-nav' },
279
+ { kind: 'element', from: 'p-panelmenu', to: 'mk-nav-list', manual: true, note: '[model] → <mk-nav-group> / <mk-nav-item> children.', docs: '/components/command-nav' },
280
+ { kind: 'element', from: 'p-panelMenu', to: 'mk-nav-list', manual: true, note: '[model] → <mk-nav-group> / <mk-nav-item> children.', docs: '/components/command-nav' },
281
+ { kind: 'element', from: 'p-breadcrumb', to: 'mk-breadcrumb', manual: true, note: '[model] → <mk-breadcrumb-item> children.', docs: '/components/navigation' },
282
+ { kind: 'element', from: 'p-dock', note: 'No dock.', docs: '/components/navigation' },
283
+ { kind: 'element', from: 'p-speeddial', to: 'mk-fab', manual: true, note: '[model] → <button mkFabAction> children.', docs: '/components/navigation' },
284
+ { kind: 'element', from: 'p-speedDial', to: 'mk-fab', manual: true, note: '[model] → <button mkFabAction> children.', docs: '/components/navigation' },
285
+ { kind: 'element', from: 'p-terminal', note: 'No terminal.', docs: '/components/data' },
286
+ ];
287
+ exports.DOCS_BASE = D;
288
+ /** package.json dependencies the migration makes obsolete. */
289
+ exports.PRIMENG_PACKAGES = ['primeng', '@primeng/themes', '@primeuix/themes', '@primeuix/styled', 'primeicons', 'primeflex'];
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "MkKitMigratePrimeng",
4
+ "title": "@mk-kit/ui migrate-primeng schematic",
5
+ "type": "object",
6
+ "properties": {
7
+ "path": {
8
+ "type": "string",
9
+ "default": "src",
10
+ "description": "Directory to migrate (TypeScript and HTML files are visited recursively)."
11
+ },
12
+ "dryRun": {
13
+ "type": "boolean",
14
+ "default": false,
15
+ "description": "Compute and print the report without writing any file.",
16
+ "alias": "d"
17
+ },
18
+ "report": {
19
+ "type": "string",
20
+ "default": "primeng-migration.md",
21
+ "description": "Path of the Markdown report to write (relative to the workspace root)."
22
+ }
23
+ },
24
+ "required": []
25
+ }