ngx-kit 6.3.0 → 7.0.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.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/angle-selector/README.md +34 -34
  3. package/box-shadow/README.md +33 -33
  4. package/color-picker/README.md +52 -49
  5. package/data-table/README.md +120 -113
  6. package/date-picker/README.md +74 -69
  7. package/dialog/README.md +92 -92
  8. package/drag-resize/README.md +55 -0
  9. package/dropzone/README.md +422 -422
  10. package/fesm2022/ngx-kit-angle-selector.mjs +2 -2
  11. package/fesm2022/ngx-kit-angle-selector.mjs.map +1 -1
  12. package/fesm2022/ngx-kit-box-shadow.mjs +2 -2
  13. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-color-picker.mjs +265 -73
  15. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-data-table.mjs +2 -2
  17. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-date-picker.mjs +7 -9
  19. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-dialog.mjs +3 -3
  21. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  22. package/fesm2022/ngx-kit-drag-resize.mjs +1664 -0
  23. package/fesm2022/ngx-kit-drag-resize.mjs.map +1 -0
  24. package/fesm2022/ngx-kit-drawer-menu.mjs +389 -285
  25. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -1
  26. package/fesm2022/ngx-kit-dropzone.mjs +2 -2
  27. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -1
  28. package/fesm2022/ngx-kit-form-field.mjs +3 -5
  29. package/fesm2022/ngx-kit-form-field.mjs.map +1 -1
  30. package/fesm2022/ngx-kit-gallery.mjs +2 -2
  31. package/fesm2022/ngx-kit-gallery.mjs.map +1 -1
  32. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  33. package/fesm2022/ngx-kit-grid-layout.mjs +927 -0
  34. package/fesm2022/ngx-kit-grid-layout.mjs.map +1 -0
  35. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -1
  36. package/fesm2022/ngx-kit-menu.mjs +8 -8
  37. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  38. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  39. package/fesm2022/ngx-kit-notify.mjs +2 -2
  40. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  41. package/fesm2022/ngx-kit-shared.mjs +54 -3
  42. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  43. package/fesm2022/ngx-kit-time-picker.mjs +2 -2
  44. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -1
  45. package/fesm2022/ngx-kit-virtual-scroll.mjs +392 -0
  46. package/fesm2022/ngx-kit-virtual-scroll.mjs.map +1 -0
  47. package/fesm2022/ngx-kit-webflow.mjs +709 -0
  48. package/fesm2022/ngx-kit-webflow.mjs.map +1 -0
  49. package/gallery/README.md +71 -71
  50. package/gradient-picker/README.md +41 -41
  51. package/grid-layout/README.md +64 -0
  52. package/image-editor/README.md +12 -12
  53. package/menu/README.md +85 -85
  54. package/message/README.md +70 -70
  55. package/notify/README.md +56 -58
  56. package/package.json +17 -1
  57. package/shared/README.md +117 -117
  58. package/time-picker/README.md +89 -95
  59. package/types/ngx-kit-color-picker.d.ts +72 -16
  60. package/types/ngx-kit-drag-resize.d.ts +368 -0
  61. package/types/ngx-kit-drawer-menu.d.ts +135 -86
  62. package/types/ngx-kit-grid-layout.d.ts +310 -0
  63. package/types/ngx-kit-image-editor.d.ts +1 -1
  64. package/types/ngx-kit-shared.d.ts +12 -1
  65. package/types/ngx-kit-virtual-scroll.d.ts +179 -0
  66. package/types/ngx-kit-webflow.d.ts +286 -0
  67. package/virtual-scroll/README.md +199 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-kit-webflow.mjs","sources":["../../../projects/libs/webflow/services/drag-drop.service.ts","../../../projects/libs/webflow/services/drop-position.service.ts","../../../projects/libs/webflow/directives/draggable.directive.ts","../../../projects/libs/webflow/directives/resizable.directive.ts","../../../projects/libs/webflow/directives/dropzone-container.directive.ts","../../../projects/libs/webflow/components/drop-indicator/drop-indicator.component.ts","../../../projects/libs/webflow/services/flow-tree.service.ts","../../../projects/libs/webflow/models/types.ts","../../../projects/libs/webflow/ngx-kit-webflow.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { DropResult } from '../models/types';\n\n/**\n * DragDropService\n * -------------------------------------------------------------\n * وضعیت سراسریِ «چه چیزی الان در حال درگ است» را نگه می‌دارد.\n * فقط signal، بدون هیچ Subject/Observable اضافه — سبک و قابل‌پیش‌بینی.\n */\n@Injectable({ providedIn: 'root' })\nexport class DragDropService {\n /** id آیتمی که هم‌اکنون درگ می‌شود، یا null */\n readonly activeId = signal<string | null>(null);\n\n /** آخرین نتیجهٔ محاسبه‌شدهٔ drop توسط DropPositionService */\n readonly pendingDrop = signal<DropResult | null>(null);\n\n startDrag(id: string): void {\n this.activeId.set(id);\n this.pendingDrop.set(null);\n }\n\n setPendingDrop(result: DropResult | null): void {\n this.pendingDrop.set(result);\n }\n\n endDrag(): DropResult | null {\n const result = this.pendingDrop();\n this.activeId.set(null);\n this.pendingDrop.set(null);\n return result;\n }\n\n get isDragging(): boolean {\n return this.activeId() !== null;\n }\n}\n","import { Injectable, signal, computed } from '@angular/core';\nimport { DropZone, IndicatorState, Rect } from '../models/types';\n\n/**\n * DropPositionService\n * -------------------------------------------------------------\n * قلب الگوریتمِ «دقیقاً مثل Webflow» اینجاست.\n *\n * نکتهٔ کلیدی پرفورمنسی: این سرویس هیچ‌وقت روی همهٔ آیتم‌های لیست حلقه نمی‌زند.\n * فقط با استفاده از event delegation (یک لیستنر روی کانتینر) و event.target\n * دقیقاً همان یک المنتی که ماوس رویش است پیدا می‌شود -> O(1) صرف‌نظر از\n * تعداد آیتم‌ها (چه ۱۰ تا باشند چه ۱۰,۰۰۰ تا).\n *\n * منطق تشخیص zone (همانی که Webflow استفاده می‌کند):\n * ۱. جهت چیدمان پدرِ آیتم هدف را می‌خوانیم (row یا column؛ از flex-direction\n * یا داده‌شده به‌صورت دستی).\n * ۲. موقعیت نسبی ماوس داخل rect آیتم هدف را به درصد تبدیل می‌کنیم.\n * ۳. اگر آیتم هدف خودش یک container (قابل‌نست) باشد و ماوس در «هستهٔ\n * مرکزی» rect باشد (مثلاً ۲۵٪ تا ۷۵٪ در هر دو محور) -> zone = inside.\n * ۴. در غیر این صورت، محور اصلیِ چیدمان (که هم‌ردیفی معنی می‌دهد) با\n * نوار نازک لبه (٪ آستانه) بررسی می‌شود:\n * - چیدمان row: نزدیک لبهٔ چپ/راست -> before/after (کنار هم)\n * نزدیک لبهٔ بالا/پایین -> above/below (ردیف جدید)\n * - چیدمان column: برعکسِ بالا\n */\n\nconst EDGE_THRESHOLD = 0.33; // ۳۳٪ نزدیک هر لبه => درج در همان محور\nconst NEST_CORE = 0.25; // فاصله از هر لبه برای اینکه «هسته» حساب شود\n\n@Injectable({ providedIn: 'root' })\nexport class DropPositionService {\n private readonly _indicator = signal<IndicatorState>({\n visible: false,\n orientation: null,\n x: 0,\n y: 0,\n length: 0,\n highlightRect: null,\n });\n\n /** استیت فقط‌خواندنیِ اندیکاتور برای بایند در تمپلیت */\n readonly indicator = computed(() => this._indicator());\n\n private lastTargetId: string | null = null;\n private lastZone: DropZone | null = null;\n\n /**\n * فراخوانی در هر pointermove حین درگ.\n * targetEl باید همان element.closest('[data-flow-id]') باشد که در\n * دایرکتیو کانتینر با event delegation پیدا شده — نه یک لوپ روی آیتم‌ها.\n */\n evaluate(params: {\n targetEl: HTMLElement;\n targetId: string;\n isContainer: boolean;\n parentAxis: 'row' | 'column';\n clientX: number;\n clientY: number;\n }): { targetId: string; zone: DropZone } {\n const { targetEl, targetId, isContainer, parentAxis, clientX, clientY } = params;\n const rect = targetEl.getBoundingClientRect();\n\n const rx = clamp((clientX - rect.left) / rect.width, 0, 1);\n const ry = clamp((clientY - rect.top) / rect.height, 0, 1);\n\n let zone: DropZone;\n\n const insideCore =\n isContainer &&\n rx > NEST_CORE && rx < 1 - NEST_CORE &&\n ry > NEST_CORE && ry < 1 - NEST_CORE;\n\n if (insideCore) {\n zone = 'inside';\n } else if (parentAxis === 'row') {\n if (rx < EDGE_THRESHOLD) zone = 'before';\n else if (rx > 1 - EDGE_THRESHOLD) zone = 'after';\n else zone = ry < 0.5 ? 'above' : 'below';\n } else {\n if (ry < EDGE_THRESHOLD) zone = 'above';\n else if (ry > 1 - EDGE_THRESHOLD) zone = 'below';\n else zone = rx < 0.5 ? 'before' : 'after';\n }\n\n this.lastTargetId = targetId;\n this.lastZone = zone;\n this.paintIndicator(rect, zone);\n\n return { targetId, zone };\n }\n\n /** رسم خط/کادر راهنما - فقط نوشتن به یک signal، بدون لمس بقیهٔ DOM */\n private paintIndicator(rect: DOMRect, zone: DropZone): void {\n const asRect: Rect = {\n top: rect.top, left: rect.left, width: rect.width, height: rect.height,\n right: rect.right, bottom: rect.bottom,\n };\n\n if (zone === 'inside') {\n this._indicator.set({\n visible: true,\n orientation: null,\n x: 0, y: 0, length: 0,\n highlightRect: asRect,\n });\n return;\n }\n\n if (zone === 'above' || zone === 'below') {\n this._indicator.set({\n visible: true,\n orientation: 'h',\n x: rect.left,\n y: zone === 'above' ? rect.top : rect.bottom,\n length: rect.width,\n highlightRect: null,\n });\n } else {\n this._indicator.set({\n visible: true,\n orientation: 'v',\n x: zone === 'before' ? rect.left : rect.right,\n y: rect.top,\n length: rect.height,\n highlightRect: null,\n });\n }\n }\n\n clear(): void {\n this.lastTargetId = null;\n this.lastZone = null;\n this._indicator.set({\n visible: false, orientation: null, x: 0, y: 0, length: 0, highlightRect: null,\n });\n }\n\n get current(): { targetId: string; zone: DropZone } | null {\n if (!this.lastTargetId || !this.lastZone) return null;\n return { targetId: this.lastTargetId, zone: this.lastZone };\n }\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, v));\n}\n","import {\n Directive, ElementRef, EventEmitter, Input, Output,\n Renderer2, effect, inject, signal, NgZone, OnDestroy, HostBinding\n} from '@angular/core';\nimport { DragDropService } from '../services/drag-drop.service';\nimport { DropPositionService } from '../services/drop-position.service';\nimport { DragStartEvent, DragEndEvent, DropZone } from '../models/types';\n\n/**\n * ngxDraggable\n * -------------------------------------------------------------\n * تنها دایرکتیو مسئول درگ. کل منطق حرکت با CSS transform (translate3d)\n * روی خودِ عنصر درگ‌شونده انجام می‌شود — نه با جابجایی واقعی در DOM لیست.\n * جابجاییِ واقعیِ داده فقط یک‌بار، در لحظهٔ drop، از طریق خروجی\n * (flowDrop) اتفاق می‌افتد و آن‌وقت مصرف‌کننده (کامپوننت کانتینر) با\n * *ngFor + trackBy مدل را آپدیت می‌کند.\n *\n * دلیل مقیاس‌پذیری با هزاران آیتم:\n * - در حین pointermove هیچ آیتم دیگری لمس/محاسبه نمی‌شود.\n * - listener مربوط به تشخیص هدف روی کانتینر (event delegation) است،\n * نه روی تک‌تک آیتم‌ها (این بخش در ContainerDropzoneDirective است).\n * - آپدیت transform با requestAnimationFrame throttle می‌شود تا از\n * چندبار layout/paint در هر فریم جلوگیری شود.\n */\n@Directive({\n selector: '[ngxDraggable]',\n standalone: true,\n exportAs: 'ngxDraggable',\n})\nexport class DraggableDirective implements OnDestroy {\n private readonly el = inject(ElementRef<HTMLElement>).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly zone = inject(NgZone);\n private readonly dragDrop = inject(DragDropService);\n private readonly dropPos = inject(DropPositionService);\n\n /** شناسهٔ یکتای بلاک — برای شناسایی هنگام درگ لازم است */\n @Input({ required: true }) ngxDraggableId!: string;\n\n /** غیرفعال کردن موقت درگ (مثلاً حین ادیت متن داخل بلاک) */\n @Input() ngxDraggableDisabled = false;\n\n /** هندلِ اختصاصی؛ اگر ندهی، کل عنصر هندل می‌شود */\n @Input() ngxDragHandleSelector: string | null = null;\n\n @Output() flowDragStart = new EventEmitter<DragStartEvent>();\n @Output() flowDragEnd = new EventEmitter<DragEndEvent>();\n\n readonly dragging = signal(false);\n\n @HostBinding('class.ngx-dragging')\n get draggingClass() { return this.dragging(); }\n\n @HostBinding('style.touchAction')\n get touchAction() { return 'none'; }\n\n private startX = 0;\n private startY = 0;\n private originLeft = 0;\n private originTop = 0;\n private rafId: number | null = null;\n private pendingTransform: { x: number; y: number } | null = null;\n private cleanupFns: Array<() => void> = [];\n\n constructor() {\n this.zone.runOutsideAngular(() => {\n this.cleanupFns.push(\n this.renderer.listen(this.el, 'pointerdown', (e: PointerEvent) => this.onPointerDown(e))\n );\n });\n }\n\n private onPointerDown(e: PointerEvent): void {\n if (this.ngxDraggableDisabled) return;\n if (e.button !== 0) return;\n\n if (this.ngxDragHandleSelector) {\n const handle = this.el.querySelector(this.ngxDragHandleSelector);\n if (!handle || !handle.contains(e.target as Node)) return;\n }\n\n e.preventDefault();\n e.stopPropagation();\n\n const rect = this.el.getBoundingClientRect();\n this.startX = e.clientX;\n this.startY = e.clientY;\n this.originLeft = rect.left;\n this.originTop = rect.top;\n\n this.el.setPointerCapture(e.pointerId);\n this.dragging.set(true);\n this.dragDrop.startDrag(this.ngxDraggableId);\n\n this.zone.run(() => {\n this.flowDragStart.emit({\n id: this.ngxDraggableId,\n pointerId: e.pointerId,\n originRect: {\n top: rect.top, left: rect.left, width: rect.width, height: rect.height,\n right: rect.right, bottom: rect.bottom,\n },\n });\n });\n\n this.renderer.addClass(this.el, 'ngx-drag-ghost');\n\n const move = (ev: PointerEvent) => this.onPointerMove(ev);\n const up = (ev: PointerEvent) => this.onPointerUp(ev, move, up);\n\n this.el.addEventListener('pointermove', move as EventListener);\n this.el.addEventListener('pointerup', up as EventListener);\n this.el.addEventListener('pointercancel', up as EventListener);\n }\n\n private onPointerMove(e: PointerEvent): void {\n const dx = e.clientX - this.startX;\n const dy = e.clientY - this.startY;\n this.pendingTransform = { x: dx, y: dy };\n\n if (this.rafId === null) {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n if (!this.pendingTransform) return;\n // تنها لمسِ DOM در کل چرخهٔ درگ: نوشتن transform روی خودِ عنصر.\n this.renderer.setStyle(\n this.el,\n 'transform',\n `translate3d(${this.pendingTransform.x}px, ${this.pendingTransform.y}px, 0)`\n );\n });\n }\n\n // نتیجهٔ zone فعلی (اگر کانتینر آن را محاسبه کرده) در سرویس در دسترس است.\n }\n\n private onPointerUp(e: PointerEvent, move: (ev: PointerEvent) => void, up: (ev: PointerEvent) => void): void {\n this.el.removeEventListener('pointermove', move as EventListener);\n this.el.removeEventListener('pointerup', up as EventListener);\n this.el.removeEventListener('pointercancel', up as EventListener);\n\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n\n this.renderer.removeStyle(this.el, 'transform');\n this.renderer.removeClass(this.el, 'ngx-drag-ghost');\n this.dragging.set(false);\n\n const result = this.dragDrop.endDrag();\n this.dropPos.clear();\n\n this.zone.run(() => {\n this.flowDragEnd.emit({ id: this.ngxDraggableId, drop: result });\n });\n }\n\n ngOnDestroy(): void {\n this.cleanupFns.forEach((fn) => fn());\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n }\n}\n","import {\n Directive, ElementRef, EventEmitter, Input, Output,\n Renderer2, inject, NgZone, OnDestroy, signal\n} from '@angular/core';\nimport { ResizeHandlePosition, ResizeMoveEvent } from '../models/types';\n\n/**\n * ngxResizable\n * -------------------------------------------------------------\n * تنها دایرکتیو مسئول ریسایز. مستقل از DraggableDirective.\n * روی عنصر اصلی قرار می‌گیرد و به همراه ۸ هندل (که خودت در تمپلیت با\n * class مشخص می‌کنی، مثلاً <span class=\"rz-handle\" data-handle=\"se\">)\n * کار می‌کند.\n *\n * فقط CSS width/height/left/top آپدیت می‌شود (از طریق خروجی flowResize)\n * و مصرف‌کننده تصمیم می‌گیرد این مقادیر را چطور به مدل/استایل بایند کند —\n * دایرکتیو خودش مستقیماً مدل داده را تغییر نمی‌دهد.\n */\n@Directive({\n selector: '[ngxResizable]',\n standalone: true,\n exportAs: 'ngxResizable',\n})\nexport class ResizableDirective implements OnDestroy {\n private readonly el = inject(ElementRef<HTMLElement>).nativeElement;\n private readonly renderer = inject(Renderer2);\n private readonly zone = inject(NgZone);\n\n @Input({ required: true }) ngxResizableId!: string;\n @Input() ngxResizableMinWidth = 24;\n @Input() ngxResizableMinHeight = 24;\n @Input() ngxResizableDisabled = false;\n\n /** انتخاب‌گر هندل‌ها؛ باید attribute یا data-handle داشته باشند */\n @Input() ngxResizeHandleSelector = '[data-handle]';\n\n @Output() flowResizeStart = new EventEmitter<{ id: string; handle: ResizeHandlePosition }>();\n @Output() flowResizeMove = new EventEmitter<ResizeMoveEvent>();\n @Output() flowResizeEnd = new EventEmitter<ResizeMoveEvent>();\n\n readonly resizing = signal(false);\n\n private startX = 0;\n private startY = 0;\n private startW = 0;\n private startH = 0;\n private handle: ResizeHandlePosition = 'se';\n private rafId: number | null = null;\n private pending: { w: number; h: number; ox: number; oy: number } | null = null;\n private unlisten: (() => void) | null = null;\n\n constructor() {\n this.zone.runOutsideAngular(() => {\n this.unlisten = this.renderer.listen(this.el, 'pointerdown', (e: PointerEvent) => this.onDown(e));\n });\n }\n\n private onDown(e: PointerEvent): void {\n if (this.ngxResizableDisabled) return;\n const handleEl = (e.target as HTMLElement)?.closest<HTMLElement>(this.ngxResizeHandleSelector);\n if (!handleEl || !this.el.contains(handleEl)) return;\n\n e.preventDefault();\n e.stopPropagation();\n\n this.handle = (handleEl.getAttribute('data-handle') as ResizeHandlePosition) || 'se';\n const rect = this.el.getBoundingClientRect();\n this.startX = e.clientX;\n this.startY = e.clientY;\n this.startW = rect.width;\n this.startH = rect.height;\n\n (e.target as HTMLElement).setPointerCapture(e.pointerId);\n this.resizing.set(true);\n this.zone.run(() => this.flowResizeStart.emit({ id: this.ngxResizableId, handle: this.handle }));\n\n const move = (ev: PointerEvent) => this.onMove(ev);\n const up = (ev: PointerEvent) => this.onUp(ev, move, up);\n handleEl.addEventListener('pointermove', move as EventListener);\n handleEl.addEventListener('pointerup', up as EventListener);\n handleEl.addEventListener('pointercancel', up as EventListener);\n }\n\n private onMove(e: PointerEvent): void {\n const dx = e.clientX - this.startX;\n const dy = e.clientY - this.startY;\n const h = this.handle;\n\n let w = this.startW;\n let ht = this.startH;\n let ox = 0, oy = 0;\n\n if (h.includes('e')) w = this.startW + dx;\n if (h.includes('w')) { w = this.startW - dx; ox = dx; }\n if (h.includes('s')) ht = this.startH + dy;\n if (h.includes('n')) { ht = this.startH - dy; oy = dy; }\n\n w = Math.max(this.ngxResizableMinWidth, w);\n ht = Math.max(this.ngxResizableMinHeight, ht);\n\n this.pending = { w, h: ht, ox, oy };\n\n if (this.rafId === null) {\n this.rafId = requestAnimationFrame(() => {\n this.rafId = null;\n if (!this.pending) return;\n this.zone.run(() => {\n this.flowResizeMove.emit({\n id: this.ngxResizableId, handle: this.handle,\n width: this.pending!.w, height: this.pending!.h,\n offsetX: this.pending!.ox, offsetY: this.pending!.oy,\n });\n });\n });\n }\n }\n\n private onUp(e: PointerEvent, move: (ev: PointerEvent) => void, up: (ev: PointerEvent) => void): void {\n const handleEl = e.target as HTMLElement;\n handleEl.removeEventListener('pointermove', move as EventListener);\n handleEl.removeEventListener('pointerup', up as EventListener);\n handleEl.removeEventListener('pointercancel', up as EventListener);\n\n if (this.rafId !== null) { cancelAnimationFrame(this.rafId); this.rafId = null; }\n this.resizing.set(false);\n\n if (this.pending) {\n this.zone.run(() => {\n this.flowResizeEnd.emit({\n id: this.ngxResizableId, handle: this.handle,\n width: this.pending!.w, height: this.pending!.h,\n offsetX: this.pending!.ox, offsetY: this.pending!.oy,\n });\n });\n }\n this.pending = null;\n }\n\n ngOnDestroy(): void {\n this.unlisten?.();\n if (this.rafId !== null) cancelAnimationFrame(this.rafId);\n }\n}\n","import {\n Directive, ElementRef, Input, NgZone, OnDestroy, OnInit, Renderer2, inject\n} from '@angular/core';\nimport { DragDropService } from '../services/drag-drop.service';\nimport { DropPositionService } from '../services/drop-position.service';\nimport { FlowAxis } from '../models/types';\n\n/**\n * ngxDropzoneContainer\n * -------------------------------------------------------------\n * روی هر کانتینری که فرزندانش قابل‌درگ‌اند‌دراپ هستند قرار می‌گیرد\n * (چه ریشهٔ صفحه، چه یک بلاک تو‌در‌تو).\n *\n * فقط یک pointermove-listener سراسری (روی document، حین یک درگ فعال)\n * دارد و با event.target.closest('[data-flow-id]') هدف را پیدا می‌کند.\n * این یعنی صرف‌نظر از اینکه چند هزار فرزند وجود دارد، هزینهٔ هر حرکتِ\n * ماوس ثابت (O(1)) است — نه O(n).\n *\n * هر فرزند مستقیمِ قابل‌درگ باید attribute زیر را داشته باشد\n * (به‌صورت خودکار توسط DraggableDirective/تمپلیت ست می‌شود):\n * [attr.data-flow-id]=\"item.id\"\n * [attr.data-flow-container]=\"isContainer ? '' : null\"\n */\n@Directive({\n selector: '[ngxDropzoneContainer]',\n standalone: true,\n exportAs: 'ngxDropzoneContainer',\n})\nexport class DropzoneContainerDirective implements OnInit, OnDestroy {\n private readonly el = inject(ElementRef<HTMLElement>).nativeElement;\n private readonly zone = inject(NgZone);\n private readonly renderer = inject(Renderer2);\n private readonly dragDrop = inject(DragDropService);\n private readonly dropPos = inject(DropPositionService);\n\n /** جهت چیدمان فرزندان مستقیم این کانتینر */\n @Input() ngxDropzoneAxis: FlowAxis = 'row';\n\n /** آیا خودِ این کانتینر می‌تواند میزبان nest شدن باشد */\n @Input() ngxDropzoneNestable = true;\n\n private unlistenMove: (() => void) | null = null;\n private unlistenLeave: (() => void) | null = null;\n\n ngOnInit(): void {\n this.zone.runOutsideAngular(() => {\n this.unlistenMove = this.renderer.listen(this.el, 'pointermove', (e: PointerEvent) => {\n if (!this.dragDrop.isDragging) return;\n this.handleMove(e);\n });\n });\n }\n\n private handleMove(e: PointerEvent): void {\n const targetEl = (e.target as HTMLElement)?.closest<HTMLElement>('[data-flow-id]');\n if (!targetEl || !this.el.contains(targetEl) || targetEl === this.el) return;\n\n const targetId = targetEl.getAttribute('data-flow-id');\n const activeId = this.dragDrop.activeId();\n if (!targetId || targetId === activeId) return; // نمی‌توان روی خودش دراپ کرد\n\n const isContainer = this.ngxDropzoneNestable && targetEl.hasAttribute('data-flow-container');\n\n const result = this.dropPos.evaluate({\n targetEl,\n targetId,\n isContainer,\n parentAxis: this.ngxDropzoneAxis,\n clientX: e.clientX,\n clientY: e.clientY,\n });\n\n this.dragDrop.setPendingDrop(result);\n }\n\n ngOnDestroy(): void {\n this.unlistenMove?.();\n this.unlistenLeave?.();\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { DropPositionService } from '../../services/drop-position.service';\n\n/**\n * FlowDropIndicatorComponent\n * -------------------------------------------------------------\n * یک‌بار در ریشهٔ صفحه‌ساز قرار می‌گیرد (position: fixed).\n * تنها المنتی است که در طول درگ مدام آپدیت می‌شود؛ بقیهٔ آیتم‌های\n * لیست دست‌نخورده باقی می‌مانند. کاملاً با computed از signal سرویس\n * تغذیه می‌شود، بدون هیچ منطق اضافه در کامپوننت.\n */\n@Component({\n selector: 'flow-drop-indicator',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n @if (indicator().visible) {\n @if (indicator().highlightRect; as r) {\n <div class=\"flow-nest-highlight\"\n [style.top.px]=\"r.top\" [style.left.px]=\"r.left\"\n [style.width.px]=\"r.width\" [style.height.px]=\"r.height\">\n </div>\n } @else if (indicator().orientation === 'h') {\n <div class=\"flow-indicator flow-indicator--h\"\n [style.top.px]=\"indicator().y\" [style.left.px]=\"indicator().x\"\n [style.width.px]=\"indicator().length\">\n </div>\n } @else if (indicator().orientation === 'v') {\n <div class=\"flow-indicator flow-indicator--v\"\n [style.top.px]=\"indicator().y\" [style.left.px]=\"indicator().x\"\n [style.height.px]=\"indicator().length\">\n </div>\n }\n }\n `,\n styles: [`\n :host { position: fixed; inset: 0; pointer-events: none; z-index: 9999; }\n .flow-indicator {\n position: fixed;\n background: var(--flow-accent, #146ef5);\n border-radius: 2px;\n pointer-events: none;\n }\n .flow-indicator--h { height: 3px; transform: translateY(-1.5px); }\n .flow-indicator--v { width: 3px; transform: translateX(-1.5px); }\n .flow-nest-highlight {\n position: fixed;\n border: 2px solid var(--flow-accent, #146ef5);\n background: color-mix(in srgb, var(--flow-accent, #146ef5) 10%, transparent);\n border-radius: 4px;\n pointer-events: none;\n }\n `],\n})\nexport class FlowDropIndicatorComponent {\n private readonly dropPos = inject(DropPositionService);\n readonly indicator = computed(() => this.dropPos.indicator());\n}\n","import { Injectable, signal, computed } from '@angular/core';\nimport { DropResult } from '../models/types';\n\nexport interface FlowNode {\n id: string;\n type: string;\n axis: 'row' | 'column';\n isContainer: boolean;\n props?: Record<string, unknown>;\n children: FlowNode[];\n}\n\n/**\n * FlowTreeService\n * -------------------------------------------------------------\n * مدل درختیِ صفحه (دقیقاً همان چیزی که Webflow \"Element Panel\" اسمش\n * می‌گذارد). تغییر مدل فقط در لحظهٔ drop رخ می‌دهد (نه در هر\n * pointermove) — به همین دلیل حتی با هزاران بلاک، re-render فقط\n * یک‌بار در پایان درگ اتفاق می‌افتد.\n *\n * پیاده‌سازی immutable-ish: فقط مسیر تغییر‌یافته کپی می‌شود، نه کل\n * درخت (structural sharing) تا با درخت‌های بزرگ هم CPU/GC اذیت نشود.\n */\n@Injectable({ providedIn: 'root' })\nexport class FlowTreeService {\n private readonly _root = signal<FlowNode>({\n id: 'root', type: 'root', axis: 'column', isContainer: true, children: [],\n });\n\n readonly root = computed(() => this._root());\n\n setRoot(node: FlowNode): void {\n this._root.set(node);\n }\n\n applyDrop(draggedId: string, drop: DropResult): void {\n const currentRoot = this._root();\n const dragged = findAndRemove(currentRoot, draggedId);\n if (!dragged.node) return;\n\n const afterRemoval = dragged.tree;\n const inserted = insertRelativeTo(afterRemoval, drop.targetId, drop.zone, dragged.node);\n if (inserted) this._root.set(inserted);\n }\n}\n\nfunction findAndRemove(node: FlowNode, id: string): { tree: FlowNode; node: FlowNode | null } {\n let removed: FlowNode | null = null;\n const idx = node.children.findIndex((c) => c.id === id);\n\n if (idx !== -1) {\n removed = node.children[idx];\n const children = [...node.children.slice(0, idx), ...node.children.slice(idx + 1)];\n return { tree: { ...node, children }, node: removed };\n }\n\n let changed = false;\n const newChildren = node.children.map((c) => {\n if (removed) return c;\n const res = findAndRemove(c, id);\n if (res.node) { removed = res.node; changed = true; return res.tree; }\n return c;\n });\n\n return { tree: changed ? { ...node, children: newChildren } : node, node: removed };\n}\n\nfunction insertRelativeTo(\n node: FlowNode, targetId: string, zone: DropResult['zone'], toInsert: FlowNode\n): FlowNode | null {\n const idx = node.children.findIndex((c) => c.id === targetId);\n\n if (idx !== -1) {\n if (zone === 'inside') {\n const target = node.children[idx];\n const updatedTarget = { ...target, children: [...target.children, toInsert] };\n const children = [...node.children];\n children[idx] = updatedTarget;\n return { ...node, children };\n }\n const insertAt = zone === 'before' || zone === 'above' ? idx : idx + 1;\n const children = [...node.children.slice(0, insertAt), toInsert, ...node.children.slice(insertAt)];\n return { ...node, children };\n }\n\n for (let i = 0; i < node.children.length; i++) {\n const res = insertRelativeTo(node.children[i], targetId, zone, toInsert);\n if (res) {\n const children = [...node.children];\n children[i] = res;\n return { ...node, children };\n }\n }\n return null;\n}\n","/**\n * ngx-flowbuilder — مدل‌های پایه\n */\n\nexport type FlowAxis = 'row' | 'column';\n\n/** موقعیت درج نسبت به آیتمی که ماوس روی آن است */\nexport type DropZone =\n | 'before' // قبل از آیتم، در همان محور چیدمان (مثلاً چپِ آیتم اگر ردیف است)\n | 'after' // بعد از آیتم، در همان محور چیدمان\n | 'above' // بالای آیتم؛ یعنی ایجاد ردیف/خط جدید قبل از آن\n | 'below' // پایین آیتم؛ ایجاد ردیف/خط جدید بعد از آن\n | 'inside'; // نِست‌شدن به‌عنوان فرزند (وقتی آیتم هدف یک container باشد)\n\nexport interface DropResult {\n targetId: string;\n zone: DropZone;\n}\n\nexport interface Rect {\n top: number;\n left: number;\n width: number;\n height: number;\n right: number;\n bottom: number;\n}\n\nexport interface IndicatorState {\n visible: boolean;\n /** خط باریک: 'h' یعنی خط افقی (جدا کردن ردیف‌ها)، 'v' یعنی خط عمودی (جدا کردن کنار هم) */\n orientation: 'h' | 'v' | null;\n x: number;\n y: number;\n length: number;\n /** حالت nest: به‌جای خط، یک کادر دور کل container هایلایت می‌شود */\n highlightRect: Rect | null;\n}\n\nexport interface DragStartEvent {\n id: string;\n pointerId: number;\n originRect: Rect;\n}\n\nexport interface DragMoveEvent {\n id: string;\n clientX: number;\n clientY: number;\n deltaX: number;\n deltaY: number;\n}\n\nexport interface DragEndEvent {\n id: string;\n drop: DropResult | null;\n}\n\nexport type ResizeHandlePosition =\n | 'n' | 's' | 'e' | 'w'\n | 'ne' | 'nw' | 'se' | 'sw';\n\nexport interface ResizeMoveEvent {\n id: string;\n handle: ResizeHandlePosition;\n width: number;\n height: number;\n /** فقط برای هندل‌های شمال/غرب که مبدأ عنصر هم جابجا می‌شود */\n offsetX: number;\n offsetY: number;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/gallery/README.md CHANGED
@@ -1,71 +1,71 @@
1
- # ngx-kit/gallery
2
-
3
- A professional image viewer: takes a list of images, navigates them with ‹ › buttons (like a carousel), has a fully configurable toolbar (zoom, rotate, download, print, fullscreen), zoom via mouse scroll or two-finger pinch, and panning via drag once zoomed in.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install ngx-kit
9
- ```
10
-
11
- ## Usage — directly in the page
12
-
13
- ```html
14
- <ngx-image-viewer [images]="images" [toolbar]="{ print: false }" />
15
- ```
16
-
17
- ```ts
18
- images: NgxImageViewerItem[] = [
19
- { src: '/img/1.jpg', alt: 'Image 1', caption: 'Alborz mountains' },
20
- { src: '/img/2.jpg', alt: 'Image 2' },
21
- ];
22
- ```
23
-
24
- ## Usage — inside a fullscreen dialog
25
-
26
- ```ts
27
- import { NgxImageViewerService } from 'ngx-kit/gallery';
28
-
29
- constructor(private viewer: NgxImageViewerService) {}
30
-
31
- openGallery() {
32
- this.viewer.open(this.images, { startIndex: 0 });
33
- }
34
- ```
35
-
36
- `NgxImageViewerComponent` doesn't depend on any dialog (it only has a `closed` output) — if you want to put it inside your own dialog (e.g. `ngx-kit/dialog`), use the component directly; the service is just a convenience shortcut.
37
-
38
- ## API
39
-
40
- ### `<ngx-image-viewer>`
41
-
42
- | Input | Type | Default | Description |
43
- | --- | --- | --- | --- |
44
- | `images` | `NgxImageViewerItem[]` **(required)** | | `{ src, alt?, caption?, downloadFileName? }` |
45
- | `startIndex` | `number` | `0` | |
46
- | `toolbar` | `NgxImageViewerToolbarConfig` | all `true` | Each button can be toggled individually (see below) |
47
- | `minZoom` / `maxZoom` / `zoomStep` | `number` | `1` / `6` / `0.4` | |
48
-
49
- | Output | Type | Description |
50
- | --- | --- | --- |
51
- | `indexChange` | `number` | The active image changed |
52
- | `closed` | `void` | The user clicked the close button or pressed Esc (the component itself doesn't close anything; that's left to the consumer) |
53
-
54
- ### `NgxImageViewerToolbarConfig`
55
-
56
- `prevNext`, `counter`, `zoomIn`, `zoomOut`, `resetZoom`, `rotateLeft`, `rotateRight`, `download`, `print`, `fullscreen`, `close` — all `boolean`, all default to `true` except `close` (`false`).
57
-
58
- ## Interactions
59
-
60
- | Gesture | Result |
61
- | --- | --- |
62
- | Mouse scroll | Zoom, relative to the point under the cursor (not the image center) |
63
- | Two-finger pinch (touch) | Zoom |
64
- | Drag with mouse or one finger (when zoomed) | Pan |
65
- | ← / → | Previous/next image |
66
- | + / - | Zoom in/out |
67
- | Esc | Emits `closed` |
68
-
69
- ## Dark mode and RTL
70
-
71
- Supported automatically.
1
+ # ngx-kit/gallery
2
+
3
+ A professional image viewer: takes a list of images, navigates them with ‹ › buttons (like a carousel), has a fully configurable toolbar (zoom, rotate, download, print, fullscreen), zoom via mouse scroll or two-finger pinch, and panning via drag once zoomed in.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## Usage — directly in the page
12
+
13
+ ```html
14
+ <ngx-image-viewer [images]="images" [toolbar]="{ print: false }" />
15
+ ```
16
+
17
+ ```ts
18
+ images: NgxImageViewerItem[] = [
19
+ { src: '/img/1.jpg', alt: 'Image 1', caption: 'Alborz mountains' },
20
+ { src: '/img/2.jpg', alt: 'Image 2' },
21
+ ];
22
+ ```
23
+
24
+ ## Usage — inside a fullscreen dialog
25
+
26
+ ```ts
27
+ import { NgxImageViewerService } from 'ngx-kit/gallery';
28
+
29
+ constructor(private viewer: NgxImageViewerService) {}
30
+
31
+ openGallery() {
32
+ this.viewer.open(this.images, { startIndex: 0 });
33
+ }
34
+ ```
35
+
36
+ `NgxImageViewerComponent` doesn't depend on any dialog (it only has a `closed` output) — if you want to put it inside your own dialog (e.g. `ngx-kit/dialog`), use the component directly; the service is just a convenience shortcut.
37
+
38
+ ## API
39
+
40
+ ### `<ngx-image-viewer>`
41
+
42
+ | Input | Type | Default | Description |
43
+ | ---------------------------------- | ------------------------------------- | ----------------- | --------------------------------------------------- |
44
+ | `images` | `NgxImageViewerItem[]` **(required)** | | `{ src, alt?, caption?, downloadFileName? }` |
45
+ | `startIndex` | `number` | `0` | |
46
+ | `toolbar` | `NgxImageViewerToolbarConfig` | all `true` | Each button can be toggled individually (see below) |
47
+ | `minZoom` / `maxZoom` / `zoomStep` | `number` | `1` / `6` / `0.4` | |
48
+
49
+ | Output | Type | Description |
50
+ | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- |
51
+ | `indexChange` | `number` | The active image changed |
52
+ | `closed` | `void` | The user clicked the close button or pressed Esc (the component itself doesn't close anything; that's left to the consumer) |
53
+
54
+ ### `NgxImageViewerToolbarConfig`
55
+
56
+ `prevNext`, `counter`, `zoomIn`, `zoomOut`, `resetZoom`, `rotateLeft`, `rotateRight`, `download`, `print`, `fullscreen`, `close` — all `boolean`, all default to `true` except `close` (`false`).
57
+
58
+ ## Interactions
59
+
60
+ | Gesture | Result |
61
+ | ------------------------------------------- | ------------------------------------------------------------------- |
62
+ | Mouse scroll | Zoom, relative to the point under the cursor (not the image center) |
63
+ | Two-finger pinch (touch) | Zoom |
64
+ | Drag with mouse or one finger (when zoomed) | Pan |
65
+ | ← / → | Previous/next image |
66
+ | + / - | Zoom in/out |
67
+ | Esc | Emits `closed` |
68
+
69
+ ## Dark mode and RTL
70
+
71
+ Supported automatically.
@@ -1,41 +1,41 @@
1
- # ngx-kit/gradient-picker
2
-
3
- A linear/radial gradient picker with multiple draggable color stops, outputting a ready-to-use CSS string.
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install ngx-kit
9
- ```
10
-
11
- ## Usage
12
-
13
- ```html
14
- <ngx-input-gradient [(ngModel)]="gradientCss"></ngx-input-gradient>
15
- ```
16
-
17
- Or as a directive on a plain input:
18
-
19
- ```html
20
- <input type="text" [ngxInputGradient]="gradientCss" (change)="gradientCss = $event" />
21
- ```
22
-
23
- The output is a valid CSS string like `linear-gradient(90deg, #ff0000 0%, #0000ff 100%)`, ready to use directly in `background`/`background-image`.
24
-
25
- ## API
26
-
27
- | Input | Type | Default | Description |
28
- | --- | --- | --- | --- |
29
- | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Panel theme |
30
- | `setInputBackground` *(directive)* | `boolean` | `true` | Sets the input's background to the selected gradient |
31
- | `change` *(directive)* | `EventEmitter<string>` | | The new gradient string |
32
-
33
- ## UI notes
34
-
35
- - Add a color stop by clicking on the gradient bar; drag to move it.
36
- - Double-click a stop to remove it (or use the delete button if shown).
37
- - Each stop's color is edited with the same `ngx-kit/color-picker` panel (this package depends on it).
38
-
39
- ## Dark mode and RTL
40
-
41
- Supported automatically.
1
+ # ngx-kit/gradient-picker
2
+
3
+ A linear/radial gradient picker with multiple draggable color stops, outputting a ready-to-use CSS string.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```html
14
+ <ngx-input-gradient [(ngModel)]="gradientCss"></ngx-input-gradient>
15
+ ```
16
+
17
+ Or as a directive on a plain input:
18
+
19
+ ```html
20
+ <input type="text" [ngxInputGradient]="gradientCss" (change)="gradientCss = $event" />
21
+ ```
22
+
23
+ The output is a valid CSS string like `linear-gradient(90deg, #ff0000 0%, #0000ff 100%)`, ready to use directly in `background`/`background-image`.
24
+
25
+ ## API
26
+
27
+ | Input | Type | Default | Description |
28
+ | ---------------------------------- | ----------------------------- | -------- | ---------------------------------------------------- |
29
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Panel theme |
30
+ | `setInputBackground` _(directive)_ | `boolean` | `true` | Sets the input's background to the selected gradient |
31
+ | `change` _(directive)_ | `EventEmitter<string>` | | The new gradient string |
32
+
33
+ ## UI notes
34
+
35
+ - Add a color stop by clicking on the gradient bar; drag to move it.
36
+ - Double-click a stop to remove it (or use the delete button if shown).
37
+ - Each stop's color is edited with the same `ngx-kit/color-picker` panel (this package depends on it).
38
+
39
+ ## Dark mode and RTL
40
+
41
+ Supported automatically.
@@ -0,0 +1,64 @@
1
+ # ngx-kit grid-layout
2
+
3
+ ## Angular 22 API
4
+
5
+ The rewrite is intentionally signal-first. Inputs use Angular signal inputs, outputs use `output()`, and the grid engine exposes `signal()`/`computed()` state. There is no RxJS-driven layout loop.
6
+
7
+ ### Layout modes
8
+
9
+ - `flow: 'free'` — the user can place items anywhere in the grid.
10
+ - `flow: 'horizontal'` — horizontal-first placement.
11
+ - `flow: 'vertical'` — vertical-first placement.
12
+ - `compact: 'none'` — preserve empty cells.
13
+ - `compact: 'vertical'` — pack upward.
14
+ - `compact: 'horizontal'` — pack toward the start edge.
15
+ - `compact: 'both'` — perform both passes.
16
+
17
+ ### RTL
18
+
19
+ Use `[dir]="'rtl'"` or `options.rtl = 'auto'`. Logical `x=0` is always the start-most column. The rendering layer maps that logical coordinate to the physical left/right edge. This keeps persisted layouts direction-independent.
20
+
21
+ ### Collision behavior
22
+
23
+ `allowOverlap` disables collision resolution. `pushItems` controls whether a dragged/resized item pushes colliding siblings during interaction. The final layout is normalized again when the pointer is released.
24
+
25
+ ### Example
26
+
27
+ ```html
28
+ <ngx-grid-layout
29
+ [dir]="direction()"
30
+ [options]="{ cols: 12, rowHeight: 48, gap: 8, compact: 'vertical', pushItems: true }"
31
+ (layoutChange)="saveLayout($event)">
32
+ @for (item of layout(); track item.id) {
33
+ <ngx-grid-item [id]="item.id!" [config]="item">
34
+ <div class="widget">{{ item.id }}</div>
35
+ </ngx-grid-item>
36
+ }
37
+ </ngx-grid-layout>
38
+ ```
39
+
40
+ `ngx-grid-item` installs drag and resize behavior on its host. Resize recognizes all eight edges/corners and uses grid snapping supplied by the grid engine.
41
+
42
+ > **Note on `[config]="item"` above:** `layout()` is a `computed()` that maps the
43
+ > internal item list to a fresh array of fresh objects on every recompute, so
44
+ > each item gets a *new* config object reference whenever anything in the grid
45
+ > changes — even if the values are identical. `NgxGridItemComponent` and
46
+ > `GridLayoutService` are written to tolerate this (they compare configs by
47
+ > value before writing to any signal), so this pattern is safe to use as-is.
48
+ > If you maintain your own item list instead, prefer keeping a stable object
49
+ > reference per item and only replacing it when its values actually change —
50
+ > it's cheaper and avoids relying on the library's internal guards.
51
+
52
+ # Grid layout API reference
53
+
54
+ | Option | Meaning |
55
+ | -------------- | ------------------------------------------------- |
56
+ | `cols` | Number of logical columns. |
57
+ | `rowHeight` | Pixel row height or `fit`. |
58
+ | `gap` | Gap between cells in pixels. |
59
+ | `flow` | Free, horizontal-first, or vertical-first intent. |
60
+ | `compact` | Compaction direction. |
61
+ | `allowOverlap` | Allow items to occupy the same cells. |
62
+ | `pushItems` | Push siblings away during interaction. |
63
+ | `rtl` | `true`, `false`, or `auto`. |
64
+ | `animate` | Reserved for the visual animation layer. |
@@ -22,18 +22,18 @@ onSaved(result: NgxImageEditorResult) {
22
22
 
23
23
  ## API
24
24
 
25
- | Input | Type | Default | Description |
26
- | --- | --- | --- | --- |
27
- | `source` | `File \| Blob \| string \| null` **(required)** | | The source file/blob/data URL |
28
- | `aspectRatio` | `number` | free | Lock the crop's aspect ratio (e.g. `1` for a square avatar) |
29
- | `outputMaxWidth` / `outputMaxHeight` | `number` | unlimited | Resize the final output's dimensions |
30
- | `outputType` | `'image/jpeg' \| 'image/png' \| 'image/webp'` | `'image/jpeg'` | |
31
- | `displayMaxWidth` | `number` | `420` | Max display width for the crop area on screen |
32
-
33
- | Output | Type | Description |
34
- | --- | --- | --- |
35
- | `saved` | `NgxImageEditorResult` (`{ blob, dataUrl, width, height }`) | |
36
- | `cancelled` | `void` | |
25
+ | Input | Type | Default | Description |
26
+ | ------------------------------------ | ----------------------------------------------- | -------------- | ----------------------------------------------------------- |
27
+ | `source` | `File \| Blob \| string \| null` **(required)** | | The source file/blob/data URL |
28
+ | `aspectRatio` | `number` | free | Lock the crop's aspect ratio (e.g. `1` for a square avatar) |
29
+ | `outputMaxWidth` / `outputMaxHeight` | `number` | unlimited | Resize the final output's dimensions |
30
+ | `outputType` | `'image/jpeg' \| 'image/png' \| 'image/webp'` | `'image/jpeg'` | |
31
+ | `displayMaxWidth` | `number` | `420` | Max display width for the crop area on screen |
32
+
33
+ | Output | Type | Description |
34
+ | ----------- | ----------------------------------------------------------- | ----------- |
35
+ | `saved` | `NgxImageEditorResult` (`{ blob, dataUrl, width, height }`) | |
36
+ | `cancelled` | `void` | |
37
37
 
38
38
  ## Internal architecture (why it's fast)
39
39
 
package/menu/README.md CHANGED
@@ -1,85 +1,85 @@
1
- # ngx-kit/menu
2
-
3
- Dropdown menu and context (right-click) menu, with smart positioning relative to an anchor (via `ngx-kit/shared`'s `OverlayService`).
4
-
5
- ## Install
6
-
7
- ```bash
8
- npm install ngx-kit
9
- ```
10
-
11
- ## Basic usage (dropdown menu)
12
-
13
- ```ts
14
- import { NgxMenuModule } from 'ngx-kit/menu';
15
-
16
- @Component({
17
- standalone: true,
18
- imports: [NgxMenuModule],
19
- template: `
20
- <button [ngxMenu]="userMenu">Open menu</button>
21
-
22
- <ngx-menu #userMenu="ngxMenu">
23
- <ngx-menu-item (click)="editProfile()">Edit profile</ngx-menu-item>
24
- <ngx-menu-item (click)="logout()">Sign out</ngx-menu-item>
25
- <ngx-menu-divider></ngx-menu-divider>
26
- <ngx-menu-item [ngxMenu]="subMenu">More settings ›</ngx-menu-item>
27
- </ngx-menu>
28
-
29
- <ngx-menu #subMenu="ngxMenu">
30
- <ngx-menu-item>Option A</ngx-menu-item>
31
- <ngx-menu-item>Option B</ngx-menu-item>
32
- </ngx-menu>
33
- `,
34
- })
35
- export class MyComponent {}
36
- ```
37
-
38
- Important: `<ngx-menu>`'s content isn't rendered until it's triggered via `[ngxMenu]` (or `[ngxContextMenu]`) — so you can't use `<ngx-menu>` directly, without a trigger, as an always-visible list (like a sidebar). For that, use a regular list styled similarly.
39
-
40
- Nested menus (submenus) work exactly as shown above, just by putting `[ngxMenu]` on the `<ngx-menu-item>` itself.
41
-
42
- ## Right-click (context) menu
43
-
44
- ```html
45
- <div [ngxContextMenu]="rightClickMenu">Right-click me</div>
46
-
47
- <ngx-menu #rightClickMenu="ngxMenu">
48
- <ngx-menu-item>Copy</ngx-menu-item>
49
- <ngx-menu-item>Paste</ngx-menu-item>
50
- </ngx-menu>
51
- ```
52
-
53
- ## API
54
-
55
- ### `[ngxMenu]` directive
56
-
57
- | Input | Type | Description |
58
- | --- | --- | --- |
59
- | `ngxMenu` | `NgxMenu \| TemplateRef` | Reference to the menu to open |
60
- | `placement` | `'top' \| 'bottom' \| 'auto'` | Opening direction; defaults to `'auto'` (picked automatically if there isn't enough room) |
61
-
62
- ### `<ngx-menu>`
63
-
64
- | Input | Type | Description |
65
- | --- | --- | --- |
66
- | `class` | `string` | Extra CSS class on the panel |
67
-
68
- ### Styling
69
-
70
- Via CSS custom properties:
71
-
72
- ```css
73
- ngx-menu {
74
- --ngx-menu-bg: light-dark(#fff, #252425);
75
- --ngx-menu-fg: light-dark(#000, #fff);
76
- --ngx-menu-radius: 10px;
77
- --ngx-menu-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
78
- --ngx-menu-item-padding: 8px 14px;
79
- --ngx-menu-item-hover-bg: #9bc6ff68;
80
- }
81
- ```
82
-
83
- ## Dark mode and RTL
84
-
85
- Both are supported automatically (via `ngx-kit/shared`'s `OverlayService`/`DirectionService` and `light-dark()`); no extra work needed.
1
+ # ngx-kit/menu
2
+
3
+ Dropdown menu and context (right-click) menu, with smart positioning relative to an anchor (via `ngx-kit/shared`'s `OverlayService`).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## Basic usage (dropdown menu)
12
+
13
+ ```ts
14
+ import { NgxMenuModule } from 'ngx-kit/menu';
15
+
16
+ @Component({
17
+ standalone: true,
18
+ imports: [NgxMenuModule],
19
+ template: `
20
+ <button [ngxMenu]="userMenu">Open menu</button>
21
+
22
+ <ngx-menu #userMenu="ngxMenu">
23
+ <ngx-menu-item (click)="editProfile()">Edit profile</ngx-menu-item>
24
+ <ngx-menu-item (click)="logout()">Sign out</ngx-menu-item>
25
+ <ngx-menu-divider></ngx-menu-divider>
26
+ <ngx-menu-item [ngxMenu]="subMenu">More settings ›</ngx-menu-item>
27
+ </ngx-menu>
28
+
29
+ <ngx-menu #subMenu="ngxMenu">
30
+ <ngx-menu-item>Option A</ngx-menu-item>
31
+ <ngx-menu-item>Option B</ngx-menu-item>
32
+ </ngx-menu>
33
+ `,
34
+ })
35
+ export class MyComponent {}
36
+ ```
37
+
38
+ Important: `<ngx-menu>`'s content isn't rendered until it's triggered via `[ngxMenu]` (or `[ngxContextMenu]`) — so you can't use `<ngx-menu>` directly, without a trigger, as an always-visible list (like a sidebar). For that, use a regular list styled similarly.
39
+
40
+ Nested menus (submenus) work exactly as shown above, just by putting `[ngxMenu]` on the `<ngx-menu-item>` itself.
41
+
42
+ ## Right-click (context) menu
43
+
44
+ ```html
45
+ <div [ngxContextMenu]="rightClickMenu">Right-click me</div>
46
+
47
+ <ngx-menu #rightClickMenu="ngxMenu">
48
+ <ngx-menu-item>Copy</ngx-menu-item>
49
+ <ngx-menu-item>Paste</ngx-menu-item>
50
+ </ngx-menu>
51
+ ```
52
+
53
+ ## API
54
+
55
+ ### `[ngxMenu]` directive
56
+
57
+ | Input | Type | Description |
58
+ | ----------- | ----------------------------- | ----------------------------------------------------------------------------------------- |
59
+ | `ngxMenu` | `NgxMenu \| TemplateRef` | Reference to the menu to open |
60
+ | `placement` | `'top' \| 'bottom' \| 'auto'` | Opening direction; defaults to `'auto'` (picked automatically if there isn't enough room) |
61
+
62
+ ### `<ngx-menu>`
63
+
64
+ | Input | Type | Description |
65
+ | ------- | -------- | ---------------------------- |
66
+ | `class` | `string` | Extra CSS class on the panel |
67
+
68
+ ### Styling
69
+
70
+ Via CSS custom properties:
71
+
72
+ ```css
73
+ ngx-menu {
74
+ --ngx-menu-bg: light-dark(#fff, #252425);
75
+ --ngx-menu-fg: light-dark(#000, #fff);
76
+ --ngx-menu-radius: 10px;
77
+ --ngx-menu-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
78
+ --ngx-menu-item-padding: 8px 14px;
79
+ --ngx-menu-item-hover-bg: #9bc6ff68;
80
+ }
81
+ ```
82
+
83
+ ## Dark mode and RTL
84
+
85
+ Both are supported automatically (via `ngx-kit/shared`'s `OverlayService`/`DirectionService` and `light-dark()`); no extra work needed.