ngx-kit 4.0.0 → 6.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 (68) hide show
  1. package/README.md +3 -2
  2. package/angle-selector/README.md +34 -0
  3. package/box-shadow/README.md +33 -0
  4. package/color-picker/README.md +52 -0
  5. package/data-table/README.md +120 -0
  6. package/date-picker/README.md +74 -0
  7. package/dialog/README.md +94 -169
  8. package/drawer-menu/README.md +76 -0
  9. package/dropzone/README.md +59 -0
  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 +28 -27
  13. package/fesm2022/ngx-kit-box-shadow.mjs.map +1 -1
  14. package/fesm2022/ngx-kit-color-picker.mjs +173 -43
  15. package/fesm2022/ngx-kit-color-picker.mjs.map +1 -1
  16. package/fesm2022/ngx-kit-data-table.mjs +446 -191
  17. package/fesm2022/ngx-kit-data-table.mjs.map +1 -1
  18. package/fesm2022/ngx-kit-date-picker.mjs +120 -86
  19. package/fesm2022/ngx-kit-date-picker.mjs.map +1 -1
  20. package/fesm2022/ngx-kit-dialog.mjs +38 -7
  21. package/fesm2022/ngx-kit-dialog.mjs.map +1 -1
  22. package/fesm2022/ngx-kit-drawer-menu.mjs +190 -0
  23. package/fesm2022/ngx-kit-drawer-menu.mjs.map +1 -0
  24. package/fesm2022/ngx-kit-dropzone.mjs +272 -0
  25. package/fesm2022/ngx-kit-dropzone.mjs.map +1 -0
  26. package/fesm2022/ngx-kit-form-field.mjs +87 -0
  27. package/fesm2022/ngx-kit-form-field.mjs.map +1 -0
  28. package/fesm2022/ngx-kit-gallery.mjs +419 -0
  29. package/fesm2022/ngx-kit-gallery.mjs.map +1 -0
  30. package/fesm2022/ngx-kit-gradient-picker.mjs +12 -4
  31. package/fesm2022/ngx-kit-gradient-picker.mjs.map +1 -1
  32. package/fesm2022/ngx-kit-image-editor.mjs +501 -0
  33. package/fesm2022/ngx-kit-image-editor.mjs.map +1 -0
  34. package/fesm2022/ngx-kit-menu.mjs +9 -4
  35. package/fesm2022/ngx-kit-menu.mjs.map +1 -1
  36. package/fesm2022/ngx-kit-message.mjs +58 -24
  37. package/fesm2022/ngx-kit-message.mjs.map +1 -1
  38. package/fesm2022/ngx-kit-notify.mjs +10 -4
  39. package/fesm2022/ngx-kit-notify.mjs.map +1 -1
  40. package/fesm2022/ngx-kit-shared.mjs +184 -88
  41. package/fesm2022/ngx-kit-shared.mjs.map +1 -1
  42. package/fesm2022/ngx-kit-time-picker.mjs +562 -0
  43. package/fesm2022/ngx-kit-time-picker.mjs.map +1 -0
  44. package/fesm2022/ngx-kit.mjs.map +1 -1
  45. package/gallery/README.md +71 -0
  46. package/gradient-picker/README.md +41 -0
  47. package/image-editor/README.md +44 -0
  48. package/menu/README.md +85 -0
  49. package/message/README.md +70 -0
  50. package/notify/README.md +56 -0
  51. package/package.json +25 -1
  52. package/shared/README.md +117 -0
  53. package/styles/all.css +27 -0
  54. package/styles/image-viewer.css +12 -0
  55. package/types/ngx-kit-box-shadow.d.ts +1 -2
  56. package/types/ngx-kit-data-table.d.ts +290 -147
  57. package/types/ngx-kit-date-picker.d.ts +1 -1
  58. package/types/ngx-kit-dialog.d.ts +1 -0
  59. package/types/ngx-kit-drawer-menu.d.ts +101 -0
  60. package/types/ngx-kit-dropzone.d.ts +84 -0
  61. package/types/ngx-kit-form-field.d.ts +31 -0
  62. package/types/ngx-kit-gallery.d.ts +168 -0
  63. package/types/ngx-kit-image-editor.d.ts +175 -0
  64. package/types/ngx-kit-menu.d.ts +1 -0
  65. package/types/ngx-kit-message.d.ts +14 -3
  66. package/types/ngx-kit-notify.d.ts +2 -1
  67. package/types/ngx-kit-shared.d.ts +70 -15
  68. package/types/ngx-kit-time-picker.d.ts +150 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-kit-time-picker.mjs","sources":["../../../projects/libs/time-picker/types/config.ts","../../../projects/libs/time-picker/components/time-picker/time-picker.ts","../../../projects/libs/time-picker/components/time-picker/time-picker.html","../../../projects/libs/time-picker/directives/time-picker.directive.ts","../../../projects/libs/time-picker/ngx-kit-time-picker.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\n\nexport class NgxTimePickerConfig {\n cancelButtonText: string = 'Cancel';\n confirmButtonText: string = 'Ok';\n amText: string = 'AM';\n pmText: string = 'PM';\n format: '12' | '24' = '12';\n minuteStep: number = 1;\n autoSwitchToMinute: boolean = true;\n}\n\nexport const DEFAULT_TIME_PICKER_CONFIG = new NgxTimePickerConfig();\nexport const NGX_TIME_PICKER_CONFIG = new InjectionToken<NgxTimePickerConfig>(\n 'ngx-time-picker-config',\n {\n factory: () => DEFAULT_TIME_PICKER_CONFIG,\n },\n);\n","import {\n Component,\n computed,\n ElementRef,\n EventEmitter,\n forwardRef,\n inject,\n input,\n model,\n OnInit,\n output,\n Output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { BrowserService } from 'ngx-kit/shared';\nimport {\n AbstractControl,\n ControlValueAccessor,\n NG_VALIDATORS,\n NG_VALUE_ACCESSOR,\n ValidationErrors,\n Validator,\n} from '@angular/forms';\nimport type { NgxTimePickerMode } from '../../types/mode';\nimport { NGX_TIME_PICKER_CONFIG } from '../../types/config';\n\n@Component({\n selector: 'ngx-time-picker',\n templateUrl: './time-picker.html',\n styleUrls: ['./time-picker.scss'],\n imports: [CommonModule],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NgxInputTimePickerComponent),\n multi: true,\n },\n {\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => NgxInputTimePickerComponent),\n multi: true,\n },\n ],\n})\nexport class NgxInputTimePickerComponent implements ControlValueAccessor, Validator, OnInit {\n protected readonly browserService = inject(BrowserService);\n\n readonly change = output<string | null>();\n readonly cancel = output<void>();\n\n protected readonly config = inject(NGX_TIME_PICKER_CONFIG);\n isDisabled = false;\n\n /**\n * Time value.\n *\n * Example:\n * 14:35\n */\n readonly value = model<string>('12:00');\n\n /**\n * 12h or 24h.\n */\n readonly format = input<'12' | '24'>(this.config.format);\n readonly amOrPm = model<'AM' | 'PM' | undefined>(this.config.format == '12' ? 'AM' : undefined);\n\n /**\n * Minute step.\n */\n readonly minuteStep = input(this.config.minuteStep);\n\n /**\n * Whether the clock is disabled.\n */\n readonly disabled = input(false);\n\n /**\n * Whether to automatically switch from hour to minute.\n */\n readonly autoSwitchToMinute = input<boolean>(this.config.autoSwitchToMinute);\n\n readonly clock = viewChild<ElementRef<SVGSVGElement>>('clock');\n\n readonly mode = signal<NgxTimePickerMode>('hour');\n\n private dragging = false;\n\n readonly parsedTime = computed(() => {\n const value = this.value();\n\n const [hour, minute] = value.split(':').map(Number);\n\n return {\n hour: Number.isFinite(hour) ? hour : 12,\n minute: Number.isFinite(minute) ? minute : 0,\n };\n });\n\n readonly displayHour = computed(() => {\n const { hour } = this.parsedTime();\n\n if (this.format() === '12') {\n const h = hour % 12;\n return h === 0 ? 12 : h;\n }\n\n return hour;\n });\n\n readonly displayMinute = computed(() => {\n return this.parsedTime().minute;\n });\n\n readonly hourNumbers = computed(() => {\n if (this.format() === '24') {\n return Array.from({ length: 24 }, (_, i) => i);\n }\n\n return Array.from({ length: 12 }, (_, i) => i + 1);\n });\n\n readonly minuteNumbers = computed(() => {\n const step = Math.max(1, 5);\n\n const values: number[] = [];\n\n for (let i = 0; i < 60; i += step) {\n values.push(i);\n }\n\n return values;\n });\n\n readonly hourAngle = computed(() => {\n const { hour } = this.parsedTime();\n\n if (this.format() === '24') {\n /*\n * MUI-like 24 hour clock.\n *\n * 0 -> 0°\n * 6 -> 90°\n * 12 -> 180°\n * 18 -> 270°\n */\n return (hour % 12) * 30;\n }\n\n const h = hour % 12;\n\n return h * 30;\n });\n\n readonly minuteAngle = computed(() => {\n return this.parsedTime().minute * 6;\n });\n\n readonly currentAngle = computed(() => {\n return this.mode() === 'hour' ? this.hourAngle() : this.minuteAngle();\n });\n\n readonly handLength = computed(() => {\n if (this.mode() === 'hour' && this.format() === '24') {\n const hour = this.parsedTime().hour;\n\n if (hour >= 13 && hour <= 23) {\n return 58;\n }\n }\n\n return 86;\n });\n\n readonly handEnd = computed(() => {\n const angle = this.currentAngle();\n\n const radians = ((angle - 90) * Math.PI) / 180;\n\n const radius = this.handLength();\n\n return {\n x: 120 + Math.cos(radians) * radius,\n y: 120 + Math.sin(radians) * radius,\n };\n });\n\n readonly selectedPosition = computed(() => {\n const angle = this.currentAngle();\n\n const radians = ((angle - 90) * Math.PI) / 180;\n\n const radius = this.mode() === 'hour' ? 82 : 82;\n\n return {\n x: 120 + Math.cos(radians) * radius,\n y: 120 + Math.sin(radians) * radius,\n };\n });\n\n protected _onChange = (value: string) => {};\n protected _onTouched = () => {};\n protected _validatorOnChange = () => {};\n constructor() {}\n\n ngOnInit(): void {}\n\n writeValue(value: string): void {\n if (!value) value = '12:00';\n const s = value.split(':');\n if (this.format() == '12') {\n if (+s[0] > 12) {\n s[0] = (+s[0] - 12).toString().padStart(2, '0');\n this.amOrPm.set('PM');\n } else {\n this.amOrPm.set('AM');\n }\n }\n this.value.set(s.join(':') + ' ' + this.amOrPm());\n }\n validate(control: AbstractControl): ValidationErrors | null {\n return null;\n }\n registerOnChange(fn: any): void {\n this._onChange = fn;\n }\n registerOnTouched(fn: any): void {\n this._onTouched = fn;\n }\n registerOnValidatorChange?(fn: () => void): void {\n this._validatorOnChange = fn;\n }\n setDisabledState(disabled: boolean): void {\n this.isDisabled = disabled;\n }\n\n startPointer(event: PointerEvent): void {\n if (this.disabled()) {\n return;\n }\n\n event.preventDefault();\n\n this.dragging = true;\n\n const target = event.currentTarget as HTMLElement;\n\n target.setPointerCapture?.(event.pointerId);\n\n this.updateFromPointer(event);\n }\n\n movePointer(event: PointerEvent): void {\n if (!this.dragging || this.disabled()) {\n return;\n }\n\n event.preventDefault();\n\n this.updateFromPointer(event);\n }\n\n endPointer(event: PointerEvent): void {\n if (!this.dragging) {\n return;\n }\n\n this.dragging = false;\n\n const target = event.currentTarget as HTMLElement;\n\n target.releasePointerCapture?.(event.pointerId);\n\n if (this.mode() === 'hour' && this.autoSwitchToMinute()) {\n this.mode.set('minute');\n }\n }\n\n selectHour(hour: number): void {\n if (this.disabled()) {\n return;\n }\n\n let normalizedHour = hour;\n\n if (this.format() === '12') {\n const currentHour = this.parsedTime().hour;\n\n const isPm = currentHour >= 12;\n\n normalizedHour = hour === 12 ? (isPm ? 12 : 0) : isPm ? hour + 12 : hour;\n }\n\n this.setTime(normalizedHour, this.parsedTime().minute);\n\n if (this.autoSwitchToMinute()) {\n this.mode.set('minute');\n }\n }\n\n selectMinute(minute: number): void {\n if (this.disabled()) {\n return;\n }\n\n this.setTime(this.parsedTime().hour, minute);\n }\n\n setMode(mode: NgxTimePickerMode): void {\n if (!this.disabled()) {\n this.mode.set(mode);\n }\n }\n\n private updateFromPointer(event: PointerEvent): void {\n const svg = this.clock()?.nativeElement;\n\n if (!svg) {\n return;\n }\n\n const rect = svg.getBoundingClientRect();\n\n /*\n * SVG viewBox = 0 0 240 240\n *\n * Convert browser coordinates\n * to SVG coordinates.\n */\n const x = ((event.clientX - rect.left) / rect.width) * 240;\n\n const y = ((event.clientY - rect.top) / rect.height) * 240;\n\n const dx = x - 120;\n const dy = y - 120;\n\n let angle = (Math.atan2(dy, dx) * 180) / Math.PI + 90;\n\n if (angle < 0) {\n angle += 360;\n }\n\n if (this.mode() === 'hour') {\n this.updateHourFromAngle(angle);\n } else {\n this.updateMinuteFromAngle(angle);\n }\n }\n\n private updateHourFromAngle(angle: number): void {\n let hour = Math.round(angle / 30);\n\n if (hour === 0 || hour === 12) {\n hour = 12;\n }\n\n if (this.format() === '24') {\n /*\n * Determine whether pointer is closer\n * to inner or outer 12-hour ring.\n *\n * For a full 24-hour implementation we use\n * the current half-day when possible.\n */\n const currentHour = this.parsedTime().hour;\n\n const currentIsPm = currentHour >= 12;\n\n if (hour !== 12) {\n hour = currentIsPm ? hour + 12 : hour;\n } else {\n hour = currentIsPm ? 12 : 0;\n }\n }\n\n this.setTime(hour, this.parsedTime().minute);\n }\n\n private updateMinuteFromAngle(angle: number): void {\n let minute = Math.round(angle / 6);\n\n minute = minute % 60;\n\n const step = Math.max(1, this.minuteStep());\n\n minute = Math.round(minute / step) * step;\n\n if (minute >= 60) {\n minute = 0;\n }\n\n this.setTime(this.parsedTime().hour, minute);\n }\n\n private setTime(hour: number, minute: number): void {\n const h = String(hour).padStart(2, '0');\n const m = String(minute).padStart(2, '0');\n\n this.value.set(`${h}:${m}`);\n }\n\n isSelectedHour(hour: number): boolean {\n const current = this.displayHour();\n\n return current === hour;\n }\n\n isSelectedMinute(minute: number): boolean {\n return this.displayMinute() === minute;\n }\n\n formatHour(hour: number): string {\n if (this.format() === '24') {\n return String(hour).padStart(2, '0');\n }\n\n return String(hour);\n }\n\n formatMinute(minute: number): string {\n return String(minute).padStart(2, '0');\n }\n\n numberPosition(index: number, total: number, radius = 94): { x: number; y: number } {\n const angle = (index / total) * 360 - 90;\n\n const radians = (angle * Math.PI) / 180;\n\n return {\n x: 120 + Math.cos(radians) * radius,\n y: 120 + Math.sin(radians) * radius,\n };\n }\n\n hourPosition(hour: number, inner = false): { x: number; y: number } {\n const normalized = hour % 12;\n\n const angle = normalized * 30 - 90;\n\n const radians = (angle * Math.PI) / 180;\n\n const radius = inner ? 58 : 94;\n\n return {\n x: 120 + Math.cos(radians) * radius,\n y: 120 + Math.sin(radians) * radius,\n };\n }\n\n minutePosition(minute: number): {\n x: number;\n y: number;\n } {\n const angle = minute * 6 - 90;\n\n const radians = (angle * Math.PI) / 180;\n\n return {\n x: 120 + Math.cos(radians) * 94,\n y: 120 + Math.sin(radians) * 94,\n };\n }\n\n ok() {\n if (this.format() == '12') {\n this.value.update((u) => u + ` ${this.amOrPm()}`);\n }\n this.change.emit(this.value());\n this._onChange(this.value());\n }\n\n close() {\n this.cancel.emit();\n }\n}\n","<div class=\"ngx-time-picker\" [class.ngx-time-picker--disabled]=\"disabled()\">\n <!-- Header -->\n <div class=\"ngx-time-picker__header\">\n <button\n type=\"button\"\n class=\"ngx-time-picker__value\"\n [class.active]=\"mode() === 'hour'\"\n [disabled]=\"disabled()\"\n (click)=\"setMode('hour')\">\n {{ formatHour(displayHour()) }}\n </button>\n\n <span class=\"ngx-time-picker__separator\">:</span>\n\n <button\n type=\"button\"\n class=\"ngx-time-picker__value\"\n [class.active]=\"mode() === 'minute'\"\n [disabled]=\"disabled()\"\n (click)=\"setMode('minute')\">\n {{ formatMinute(displayMinute()) }}\n </button>\n\n @if (format() == '12') {\n <div class=\"ngx-time-picker_format\">\n <button [class.active]=\"amOrPm() == 'AM'\" (click)=\"amOrPm.set('AM')\">\n {{ config.amText }}\n </button>\n <button [class.active]=\"amOrPm() == 'PM'\" (click)=\"amOrPm.set('PM')\">\n {{ config.pmText }}\n </button>\n </div>\n }\n </div>\n\n <!-- Clock -->\n <div class=\"ngx-time-picker__clock-wrapper\">\n <svg\n #clock\n class=\"ngx-time-picker__clock\"\n viewBox=\"0 0 240 240\"\n xmlns=\"http://www.w3.org/2000/svg\"\n (pointerdown)=\"startPointer($event)\"\n (pointermove)=\"movePointer($event)\"\n (pointerup)=\"endPointer($event)\"\n (pointercancel)=\"endPointer($event)\">\n <!-- Background -->\n <circle class=\"clock-background\" cx=\"120\" cy=\"120\" r=\"112\" />\n\n <!-- Selected hand line -->\n <line class=\"clock-hand\" x1=\"120\" y1=\"120\" [attr.x2]=\"handEnd().x\" [attr.y2]=\"handEnd().y\" />\n\n <!-- Selected circle -->\n <circle\n class=\"clock-selected\"\n [attr.cx]=\"selectedPosition().x\"\n [attr.cy]=\"selectedPosition().y\"\n r=\"18\" />\n\n <!-- Center -->\n <circle class=\"clock-center\" cx=\"120\" cy=\"120\" r=\"5\" />\n\n <!-- HOURS -->\n @if (mode() === 'hour') {\n @for (hour of hourNumbers(); track hour) {\n @if (format() === '24' && hour >= 13) {\n <g\n class=\"clock-number clock-number--inner\"\n [class.selected]=\"isSelectedHour(hour)\"\n (click)=\"selectHour(hour)\">\n <circle\n [attr.cx]=\"hourPosition(hour - 12, true).x\"\n [attr.cy]=\"hourPosition(hour - 12, true).y\"\n r=\"16\" />\n\n <text\n [attr.x]=\"hourPosition(hour - 12, true).x\"\n [attr.y]=\"hourPosition(hour - 12, true).y\">\n {{ formatHour(hour) }}\n </text>\n </g>\n } @else {\n <g\n class=\"clock-number\"\n [class.selected]=\"isSelectedHour(hour)\"\n (click)=\"selectHour(hour)\">\n <circle [attr.cx]=\"hourPosition(hour).x\" [attr.cy]=\"hourPosition(hour).y\" r=\"18\" />\n\n <text [attr.x]=\"hourPosition(hour).x\" [attr.y]=\"hourPosition(hour).y\">\n {{ formatHour(hour) }}\n </text>\n </g>\n }\n }\n }\n\n <!-- MINUTES -->\n @if (mode() === 'minute') {\n @for (minute of minuteNumbers(); track minute) {\n <g\n class=\"clock-number\"\n [class.selected]=\"isSelectedMinute(minute)\"\n (click)=\"selectMinute(minute)\">\n <circle\n [attr.cx]=\"minutePosition(minute).x\"\n [attr.cy]=\"minutePosition(minute).y\"\n r=\"18\" />\n\n <text [attr.x]=\"minutePosition(minute).x\" [attr.y]=\"minutePosition(minute).y\">\n {{ formatMinute(minute) }}\n </text>\n </g>\n }\n }\n </svg>\n </div>\n <div class=\"ngx-time-picker--footer\">\n <button (click)=\"close()\">\n {{ config.cancelButtonText }}\n </button>\n\n <button (click)=\"ok()\">\n {{ config.confirmButtonText }}\n </button>\n </div>\n</div>\n","import {\n Directive,\n ElementRef,\n EventEmitter,\n forwardRef,\n HostListener,\n inject,\n input,\n model,\n output,\n Output,\n Renderer2,\n signal,\n ViewContainerRef,\n} from '@angular/core';\nimport {\n AbstractControl,\n ControlValueAccessor,\n NG_VALIDATORS,\n NG_VALUE_ACCESSOR,\n ValidationErrors,\n Validator,\n} from '@angular/forms';\nimport { OverlayRef, OverlayService } from 'ngx-kit/shared';\nimport { NgxInputTimePickerComponent } from '../components/time-picker/time-picker';\nimport { NGX_TIME_PICKER_CONFIG } from '../types/config';\n\n@Directive({\n selector: '[ngxInputTimePicker]',\n exportAs: 'ngxInputTimePicker',\n host: {\n class: 'ngx-datepicker-input',\n '[attr.readOnly]': 'true',\n },\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => NgxInputTimePicker),\n multi: true,\n },\n {\n provide: NG_VALIDATORS,\n useExisting: forwardRef(() => NgxInputTimePicker),\n multi: true,\n },\n ],\n})\nexport class NgxInputTimePicker implements ControlValueAccessor, Validator {\n protected readonly config = inject(NGX_TIME_PICKER_CONFIG);\n\n openOnCLick = input<boolean>(true);\n\n readonly change = output<string | null>();\n protected readonly value = signal<string>('');\n\n readonly format = input<'12' | '24'>(this.config.format);\n readonly amOrPm = model<'AM' | 'PM'>();\n\n private pickerRef?: OverlayRef<NgxInputTimePickerComponent>;\n\n protected _onChange = (value: string | null | undefined) => {};\n protected _onTouched = () => {};\n protected _validatorOnChange = () => {};\n\n private isDisabled = false;\n\n private readonly overlayService = inject(OverlayService);\n private readonly viewContainerRef = inject(ViewContainerRef);\n private readonly renderer = inject(Renderer2);\n constructor(private el: ElementRef<HTMLInputElement>) {}\n\n ngOnDestroy(): void {\n this.destroy();\n }\n\n @HostListener('click', ['$event'])\n onClick(ev: Event) {\n if (this.openOnCLick() && !this.isDisabled) {\n ev.stopPropagation();\n ev.preventDefault();\n this.toggle();\n }\n }\n\n @HostListener('input', ['$event'])\n onInput(event: Event) {\n const input = event.target as HTMLInputElement;\n this.value.set(input.value ?? '');\n this._formatValue();\n this._onChange(this.value());\n }\n\n @HostListener('blur')\n onBlur() {\n this._onTouched();\n }\n\n writeValue(value: string): void {\n this.value.set(value);\n this._formatValue();\n }\n\n registerOnChange(fn: any): void {\n this._onChange = fn;\n }\n registerOnTouched(fn: any): void {\n this._onTouched = fn;\n }\n registerOnValidatorChange?(fn: () => void): void {\n this._validatorOnChange = fn;\n }\n setDisabledState(disabled: boolean): void {\n this.isDisabled = disabled;\n if (disabled) {\n this.renderer.setProperty(this.el.nativeElement, 'disabled', disabled);\n } else {\n this.renderer.removeAttribute(this.el.nativeElement, 'disabled');\n }\n }\n\n public toggle() {\n if (this.pickerRef || this.isDisabled) {\n this.destroy();\n return;\n }\n\n this.pickerRef = this.overlayService.open({\n anchor: this.el.nativeElement,\n component: NgxInputTimePickerComponent,\n viewContainerRef: this.viewContainerRef,\n alignment: 'center',\n placement: 'bottom',\n margin: 2,\n configure: (instance, ref) => {\n instance.writeValue(this.value());\n instance.amOrPm.set(this.amOrPm());\n\n instance.change.subscribe((c: string | null) => {\n this.value.set(c ?? '');\n this.emitChange();\n this.destroy();\n });\n\n instance.cancel.subscribe(() => ref.close());\n },\n onClosed: () => {\n this.pickerRef = undefined;\n },\n });\n }\n\n private destroy() {\n this.pickerRef?.close();\n this.pickerRef = undefined;\n }\n private async emitChange() {\n this._onChange(this.value());\n this._formatValue();\n this.change.emit(this.value());\n this._onTouched();\n }\n\n validate(control: AbstractControl): ValidationErrors | null {\n return null;\n }\n\n protected _formatValue() {\n const s = this.value().split(':');\n if (this.format() == '12') {\n if (+s[0] > 12) {\n s[0] = (+s[0] - 12).toString().padStart(2, '0');\n this.amOrPm.set('PM');\n } else {\n this.amOrPm.set('AM');\n }\n }\n this.value.set(s.join(':') + ' ' + this.amOrPm());\n\n this.renderer.setProperty(this.el.nativeElement, 'value', this.value());\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-kit.mjs","sources":["../../../projects/libs/public-api.ts","../../../projects/libs/ngx-kit.ts"],"sourcesContent":["export const NGX_INPUT = '@ngxInput';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAO,MAAM,SAAS,GAAG;;ACAzB;;AAEG;;;;"}
1
+ {"version":3,"file":"ngx-kit.mjs","sources":["../../../projects/libs/public-api.ts","../../../projects/libs/ngx-kit.ts"],"sourcesContent":["export const NGX_INPUT = '@ngxInput';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAO,MAAM,SAAS,GAAG;;ACAzB;;AAEG;;;;"}
@@ -0,0 +1,71 @@
1
+ # ngx-kit/gallery
2
+
3
+ ویوئرِ حرفه‌ایِ تصویر: یه لیست تصویر می‌گیره، با دکمه‌های ‹ › (مثلِ کاروسل) بین‌شون می‌رید، نوارِ ابزارِ کاملاً قابل‌تنظیم (زوم، چرخش، دانلود، پرینت، تمام‌صفحه)، زوم با اسکرول موس یا پینچِ دوانگشتی، و پن با درگ وقتی زوم‌شده.
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## استفاده — مستقیم توی صفحه
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: 'تصویر ۱', caption: 'کوه‌های البرز' },
20
+ { src: '/img/2.jpg', alt: 'تصویر ۲' },
21
+ ];
22
+ ```
23
+
24
+ ## استفاده — داخلِ یه دیالوگِ تمام‌صفحه
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` به هیچ دیالوگی وابسته نیست (فقط یه خروجیِ `closed` داره) — اگه می‌خواید داخلِ دیالوگِ خودتون (مثلاً `ngx-kit/dialog`) بذاریدش، مستقیم از خودِ کامپوننت استفاده کنید؛ سرویس فقط یه میان‌بره.
37
+
38
+ ## API
39
+
40
+ ### `<ngx-image-viewer>`
41
+
42
+ | ورودی | نوع | پیش‌فرض | توضیح |
43
+ | ---------------------------------- | ----------------------------------- | ----------------- | -------------------------------------------- |
44
+ | `images` | `NgxImageViewerItem[]` **(اجباری)** | | `{ src, alt?, caption?, downloadFileName? }` |
45
+ | `startIndex` | `number` | `0` | |
46
+ | `toolbar` | `NgxImageViewerToolbarConfig` | همه `true` | هر دکمه جدا فعال/غیرفعال می‌شه (پایین‌تر) |
47
+ | `minZoom` / `maxZoom` / `zoomStep` | `number` | `1` / `6` / `0.4` | |
48
+
49
+ | خروجی | نوع | توضیح |
50
+ | ------------- | -------- | ----------------------------------------------------------------------------------------------- |
51
+ | `indexChange` | `number` | تغییرِ تصویرِ فعال |
52
+ | `closed` | `void` | کاربر دکمه‌ی بستن رو زد یا Esc رو فشرد (خودِ کامپوننت چیزی رو نمی‌بنده؛ تصمیم با مصرف‌کننده‌ست) |
53
+
54
+ ### `NgxImageViewerToolbarConfig`
55
+
56
+ `prevNext`, `counter`, `zoomIn`, `zoomOut`, `resetZoom`, `rotateLeft`, `rotateRight`, `download`, `print`, `fullscreen`, `close` — همه `boolean`، پیش‌فرضِ همه `true` به‌جز `close` (`false`).
57
+
58
+ ## تعامل‌ها
59
+
60
+ | ژست | نتیجه |
61
+ | -------------------------------------- | ----------------------------------------------------- |
62
+ | اسکرولِ موس | زوم، نسبت به همون نقطه‌ی زیرِ cursor (نه مرکزِ تصویر) |
63
+ | پینچِ دوانگشتی (تاچ) | زوم |
64
+ | درگ با موس یا تک‌انگشتی (وقتی زوم‌شده) | پن |
65
+ | ← / → | تصویرِ قبلی/بعدی |
66
+ | + / - | زوم این/اوت |
67
+ | Esc | امیتِ `closed` |
68
+
69
+ ## دارک‌مود و RTL
70
+
71
+ خودکار پشتیبانی می‌شه.
@@ -0,0 +1,41 @@
1
+ # ngx-kit/gradient-picker
2
+
3
+ انتخاب‌گر گرادیانِ خطی/شعاعی با چند color-stop قابل‌درگ، خروجیِ رشته‌ی CSS آماده‌ی استفاده.
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## استفاده
12
+
13
+ ```html
14
+ <ngx-input-gradient [(ngModel)]="gradientCss"></ngx-input-gradient>
15
+ ```
16
+
17
+ یا به‌عنوان دایرکتیو روی یه input معمولی:
18
+
19
+ ```html
20
+ <input type="text" [ngxInputGradient]="gradientCss" (change)="gradientCss = $event" />
21
+ ```
22
+
23
+ مقدار خروجی یه رشته‌ی معتبرِ CSS مثل `linear-gradient(90deg, #ff0000 0%, #0000ff 100%)` هست که مستقیم توی `background`/`background-image` قابل‌استفاده‌ست.
24
+
25
+ ## API
26
+
27
+ | ورودی | نوع | پیش‌فرض | توضیح |
28
+ | --------------------------------- | ----------------------------- | -------- | ------------------------------------------------------- |
29
+ | `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | تمِ پنل |
30
+ | `setInputBackground` _(دایرکتیو)_ | `boolean` | `true` | پس‌زمینه‌ی input رو به گرادیانِ انتخاب‌شده تنظیم می‌کنه |
31
+ | `change` _(دایرکتیو)_ | `EventEmitter<string>` | | رشته‌ی گرادیانِ جدید |
32
+
33
+ ## نکات UI
34
+
35
+ - هر color-stop با کلیک روی نوارِ گرادیان اضافه می‌شه و با درگ جابه‌جا می‌شه.
36
+ - برای حذف یه stop، دوبار کلیک روش کنید (یا دکمه‌ی حذف اگه نمایش داده بشه).
37
+ - برای تنظیم رنگِ هر stop، از همون پنلِ `ngx-kit/color-picker` استفاده می‌شه (این پکیج بهش وابسته‌ست).
38
+
39
+ ## دارک‌مود و RTL
40
+
41
+ خودکار پشتیبانی می‌شه.
@@ -0,0 +1,44 @@
1
+ # ngx-kit/image-editor
2
+
3
+ ویرایشگر تصویر روی پایه‌ی Canvas خام: کراپ با گوشه‌های قابل‌درگ، چرخش (سریع ۹۰° و آزاد)، روشنایی/کنتراست/اشباع، فیلترهای آماده (سیاه‌وسفید، سپیا، معکوس)، یه فیلترِ **کارتونی واقعی** (Posterize + لبه‌یابی Sobel، دستی پیاده‌سازی‌شده چون معادل بومی نداره)، و فشرده‌سازیِ خروجی با کیفیتِ قابل‌تنظیم.
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## استفاده
12
+
13
+ ```html
14
+ <ngx-image-editor [source]="selectedFile" (saved)="onSaved($event)" (cancelled)="onCancelled()" />
15
+ ```
16
+
17
+ ```ts
18
+ onSaved(result: NgxImageEditorResult) {
19
+ // result.blob (برای آپلود)، result.dataUrl (برای پیش‌نمایش فوری)، result.width/height
20
+ }
21
+ ```
22
+
23
+ ## API
24
+
25
+ | ورودی | نوع | پیش‌فرض | توضیح |
26
+ | ------------------------------------ | --------------------------------------------- | -------------- | --------------------------------------------- |
27
+ | `source` | `File \| Blob \| string \| null` **(اجباری)** | | فایل/بلاب/data-URL منبع |
28
+ | `aspectRatio` | `number` | آزاد | قفلِ نسبتِ کراپ (مثلاً `1` برای آواتار مربعی) |
29
+ | `outputMaxWidth` / `outputMaxHeight` | `number` | بدون محدودیت | فشرده‌سازیِ ابعاد در خروجیِ نهایی |
30
+ | `outputType` | `'image/jpeg' \| 'image/png' \| 'image/webp'` | `'image/jpeg'` | |
31
+ | `displayMaxWidth` | `number` | `420` | حداکثر عرضِ نمایشِ ناحیه‌ی کراپ روی صفحه |
32
+
33
+ | خروجی | نوع | توضیح |
34
+ | ----------- | ----------------------------------------------------------- | ----- |
35
+ | `saved` | `NgxImageEditorResult` (`{ blob, dataUrl, width, height }`) | |
36
+ | `cancelled` | `void` | |
37
+
38
+ ## معماریِ داخلی (چرا سریعه)
39
+
40
+ تمام تعاملِ زنده (چرخوندن، جابه‌جا/ریسایزِ کراپ‌باکس، پیش‌نمایشِ فیلترها حتی کارتونی) روی یه کپیِ کوچیک‌شده از تصویر (حداکثر ۱۲۰۰px) انجام می‌شه — فقط لحظه‌ی `save()`، رندرِ نهایی از روی تصویرِ اصلیِ کامل انجام می‌شه. `brightness`/`contrast`/`saturate`/`grayscale`/`sepia`/`invert` همه با `ctx.filter` بومیِ Canvas 2D پیاده شدن (شتاب‌دهی‌شده توسطِ مرورگر)؛ فقط فیلترِ کارتونی (که معادلِ بومی نداره) با پردازشِ پیکسلی جداگانه انجام می‌شه.
41
+
42
+ ## دارک‌مود و RTL
43
+
44
+ خودکار پشتیبانی می‌شه.
package/menu/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # ngx-kit/menu
2
+
3
+ منوی کشویی و منوی راست‌کلیک (context menu)، با موقعیت‌دهیِ هوشمند نسبت به anchor (از `ngx-kit/shared`'s `OverlayService`).
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## استفاده‌ی پایه (منوی کشویی)
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">باز کردن منو</button>
21
+
22
+ <ngx-menu #userMenu="ngxMenu">
23
+ <ngx-menu-item (click)="editProfile()">ویرایش پروفایل</ngx-menu-item>
24
+ <ngx-menu-item (click)="logout()">خروج</ngx-menu-item>
25
+ <ngx-menu-divider></ngx-menu-divider>
26
+ <ngx-menu-item [ngxMenu]="subMenu">تنظیمات بیشتر ›</ngx-menu-item>
27
+ </ngx-menu>
28
+
29
+ <ngx-menu #subMenu="ngxMenu">
30
+ <ngx-menu-item>گزینه‌ی الف</ngx-menu-item>
31
+ <ngx-menu-item>گزینه‌ی ب</ngx-menu-item>
32
+ </ngx-menu>
33
+ `,
34
+ })
35
+ export class MyComponent {}
36
+ ```
37
+
38
+ نکته‌ی مهم: محتوای `<ngx-menu>` تا وقتی از طریق `[ngxMenu]` (یا `[ngxContextMenu]`) trigger نشه رندر نمی‌شه — یعنی `<ngx-menu>` رو نمی‌شه مستقیم و بدون یه trigger، به‌عنوان یه لیستِ همیشه-نمایان (مثل یه سایدبار) استفاده کرد؛ برای اون منظور از یه لیست معمولی با استایل مشابه استفاده کنید.
39
+
40
+ منوی تودرتو (زیرمنو) هم همون‌طور که بالا دیدید، فقط با گذاشتن `[ngxMenu]` روی خودِ `<ngx-menu-item>` کار می‌کنه.
41
+
42
+ ## منوی راست‌کلیک
43
+
44
+ ```html
45
+ <div [ngxContextMenu]="rightClickMenu">راست‌کلیک کن روی من</div>
46
+
47
+ <ngx-menu #rightClickMenu="ngxMenu">
48
+ <ngx-menu-item>کپی</ngx-menu-item>
49
+ <ngx-menu-item>چسباندن</ngx-menu-item>
50
+ </ngx-menu>
51
+ ```
52
+
53
+ ## API
54
+
55
+ ### دایرکتیو `[ngxMenu]`
56
+
57
+ | ورودی | نوع | توضیح |
58
+ | ----------- | ----------------------------- | -------------------------------------------------------------------- |
59
+ | `ngxMenu` | `NgxMenu \| TemplateRef` | رفرنسِ منویی که باید باز بشه |
60
+ | `placement` | `'top' \| 'bottom' \| 'auto'` | جهتِ باز شدن؛ پیش‌فرض `'auto'` (خودکار انتخاب می‌شه اگه فضا کم باشه) |
61
+
62
+ ### `<ngx-menu>`
63
+
64
+ | ورودی | نوع | توضیح |
65
+ | ------- | -------- | ----------------------- |
66
+ | `class` | `string` | کلاسِ CSS اضافی روی پنل |
67
+
68
+ ### شخصی‌سازی ظاهر
69
+
70
+ از طریق 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
+ ## دارک‌مود و RTL
84
+
85
+ هر دو خودکار پشتیبانی می‌شن (از طریق `ngx-kit/shared`'s `OverlayService`/`DirectionService` و `light-dark()`)؛ کار اضافه‌ای لازم نیست.
@@ -0,0 +1,70 @@
1
+ # ngx-kit/message
2
+
3
+ دیالوگ‌های alert/confirm (شبیه SweetAlert)، با API استاتیک قابل‌فراخوانی از هرجای اپ.
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## راه‌اندازی
12
+
13
+ ``` typescript
14
+ // app.config.ts
15
+ import { provideMessage } from 'ngx-kit/message';
16
+
17
+ export const appConfig: ApplicationConfig = {
18
+ providers: [provideMessage({ confirmButtonText: 'باشه' /* پیش‌فرض‌های سراسری */ })],
19
+ };
20
+ ```
21
+
22
+ ## استفاده
23
+
24
+ ```ts
25
+ import { MSG } from 'ngx-kit/message';
26
+
27
+ MSG.success('ذخیره شد!', 'تغییرات با موفقیت ثبت شدن.');
28
+ MSG.error('خطا', 'مشکلی پیش اومد.');
29
+ MSG.warning('هشدار', 'مطمئنید؟');
30
+ MSG.info('اطلاع', 'این یه پیامِ اطلاعاتیه.');
31
+ MSG.question('سؤال', 'ادامه بدیم؟');
32
+ MSG.loading('در حال پردازش…');
33
+
34
+ // کنترلِ کامل روی گزینه‌ها:
35
+ const result = MSG.show({
36
+ title: 'حذف شود؟',
37
+ text: 'این عمل قابل بازگشت نیست.',
38
+ showCancelButton: true,
39
+ showDenyButton: true,
40
+ confirmButtonText: 'بله، حذف کن',
41
+ });
42
+ result.afterClose.subscribe((r) => console.log(r));
43
+ ```
44
+
45
+ ## API
46
+
47
+ ### `MSG` (و alias آن `Modal`)
48
+
49
+ | متد | امضا | توضیح |
50
+ | ----------------------------------------------------------------- | -------------------------- | --------------- |
51
+ | `show(options?)` | `IMessageOptions` | کنترلِ کامل |
52
+ | `info` / `success` / `warning` / `error` / `question` / `loading` | `(title, text?, options?)` | میان‌برهای رایج |
53
+
54
+ ### `IMessageOptions` (مهم‌ترین فیلدها)
55
+
56
+ | فیلد | نوع | پیش‌فرض | توضیح |
57
+ | ----------------------------------------------------------- | ------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- |
58
+ | `title` / `text` / `html` | `string` | | محتوا (`html` سنیتایز نمی‌شه — مسئولیتِ escape با خودتونه) |
59
+ | `icon` | `MessageIcon` | | آیکونِ نمایشی |
60
+ | `showConfirmButton` / `showDenyButton` / `showCancelButton` | `boolean` | `true` / `false` / `false` | |
61
+ | `confirmButtonText` / `denyButtonText` / `cancelButtonText` | `string` | `'OK'` / `'No'` / `'Cancel'` | |
62
+ | `allowOutsideClick` / `allowEscapeKey` / `allowEnterKey` | `boolean` | `true` | نحوه‌ی بستنِ پیام |
63
+ | `showCloseButton` | `boolean` | `false` | دکمه‌ی ✕ |
64
+ | `useOverlay` | `boolean` | | برای وقتی که داخل یه دیالوگِ دیگه (مثلاً Angular Material) استفاده می‌شه، لایه‌ی نمایشی رو به بالاترین سطح می‌بره |
65
+
66
+ اگه چند پیام هم‌زمان باز باشن، Escape/Enter فقط روی **آخرین (بالاترین) پیام** اثر می‌کنه، نه همه‌شون.
67
+
68
+ ## دارک‌مود و RTL
69
+
70
+ خودکار پشتیبانی می‌شه.
@@ -0,0 +1,56 @@
1
+ # ngx-kit/notify
2
+
3
+ نوتیفیکیشن/toast گوشه‌ی صفحه، با API استاتیک، صف‌بندیِ خودکار (وقتی تعداد از حد مجاز بیشتر بشه)، و مکث‌کردنِ تایمر روی هاور.
4
+
5
+ ## نصب
6
+
7
+ ```bash
8
+ npm install ngx-kit
9
+ ```
10
+
11
+ ## راه‌اندازی
12
+
13
+ ```ts
14
+ // app.config.ts
15
+ import { provideNotify } from 'ngx-kit/notify';
16
+
17
+ export const appConfig: ApplicationConfig = {
18
+ providers: [provideNotify({ timeout: 4000, position: 'top-center', dismissible: true })],
19
+ };
20
+ ```
21
+
22
+ ## استفاده
23
+
24
+ ```ts
25
+ import { Notify } from 'ngx-kit/notify';
26
+
27
+ Notify.success('ذخیره شد');
28
+ Notify.error('پیام رو نتونستیم ارسال کنیم', 'دوباره تلاش کنید');
29
+ Notify.warning('اتصال ضعیف است');
30
+ Notify.info('نسخه‌ی جدید موجوده', undefined, { timeout: 8000 });
31
+ ```
32
+
33
+ ## API
34
+
35
+ ### `Notify`
36
+
37
+ | متد | امضا |
38
+ | --------------------------------------------- | --------------------------------------------------- |
39
+ | `show(type, message, description?, options?)` | `type: 'info' \| 'success' \| 'warning' \| 'error'` |
40
+ | `info` / `success` / `warning` / `error` | `(message, description?, options?)` |
41
+
42
+ ### `NgxNotifyOptions`
43
+
44
+ | فیلد | نوع | پیش‌فرض | توضیح |
45
+ | -------------- | ----------------------- | -------------- | ---------------------------------------------------------- |
46
+ | `timeout` | `number` (ms) | `3000` | مدتِ نمایش قبل از بسته‌شدنِ خودکار |
47
+ | `position` | `NgxNotifyPositionType` | `'top-center'` | گوشه/مرکزِ نمایش |
48
+ | `maxVisible` | `number` | `10` | بیشتر از این تعداد صف می‌شن، نه هم‌پوشانی |
49
+ | `allowHtml` | `boolean` | `false` | اگه `true`، پیام به‌عنوان HTML رندر می‌شه (سنیتایز نمی‌شه) |
50
+ | `pauseOnHover` | `boolean` | `true` | تایمر با هاور موس متوقف می‌شه |
51
+ | `dismissible` | `boolean` | `true` | نمایشِ دکمه‌ی بستن |
52
+ | `closeOnTap` | `boolean` | `true` | با کلیک روی خودِ نوتیفیکیشن بسته بشه |
53
+
54
+ ## دارک‌مود و RTL
55
+
56
+ خودکار پشتیبانی می‌شه.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-kit",
3
- "version": "4.0.0",
3
+ "version": "6.0.0",
4
4
  "description": "Angular input components",
5
5
  "author": "Mohammadreza Samani <mr.samani1368@gmail.com>",
6
6
  "license": "MIT",
@@ -57,10 +57,30 @@
57
57
  "types": "./types/ngx-kit-dialog.d.ts",
58
58
  "default": "./fesm2022/ngx-kit-dialog.mjs"
59
59
  },
60
+ "./drawer-menu": {
61
+ "types": "./types/ngx-kit-drawer-menu.d.ts",
62
+ "default": "./fesm2022/ngx-kit-drawer-menu.mjs"
63
+ },
64
+ "./dropzone": {
65
+ "types": "./types/ngx-kit-dropzone.d.ts",
66
+ "default": "./fesm2022/ngx-kit-dropzone.mjs"
67
+ },
68
+ "./form-field": {
69
+ "types": "./types/ngx-kit-form-field.d.ts",
70
+ "default": "./fesm2022/ngx-kit-form-field.mjs"
71
+ },
72
+ "./gallery": {
73
+ "types": "./types/ngx-kit-gallery.d.ts",
74
+ "default": "./fesm2022/ngx-kit-gallery.mjs"
75
+ },
60
76
  "./gradient-picker": {
61
77
  "types": "./types/ngx-kit-gradient-picker.d.ts",
62
78
  "default": "./fesm2022/ngx-kit-gradient-picker.mjs"
63
79
  },
80
+ "./image-editor": {
81
+ "types": "./types/ngx-kit-image-editor.d.ts",
82
+ "default": "./fesm2022/ngx-kit-image-editor.mjs"
83
+ },
64
84
  "./menu": {
65
85
  "types": "./types/ngx-kit-menu.d.ts",
66
86
  "default": "./fesm2022/ngx-kit-menu.mjs"
@@ -76,6 +96,10 @@
76
96
  "./shared": {
77
97
  "types": "./types/ngx-kit-shared.d.ts",
78
98
  "default": "./fesm2022/ngx-kit-shared.mjs"
99
+ },
100
+ "./time-picker": {
101
+ "types": "./types/ngx-kit-time-picker.d.ts",
102
+ "default": "./fesm2022/ngx-kit-time-picker.mjs"
79
103
  }
80
104
  },
81
105
  "type": "module"
@@ -0,0 +1,117 @@
1
+ # ngx-kit/shared
2
+
3
+ ابزارها و سرویس‌های مشترکی که بقیه‌ی بسته‌های `ngx-kit` روشون بنا شدن: مدیریت اورلی/دیالوگ، تشخیص جهت صفحه (RTL/LTR)، تشخیص تنظیمات مرورگر، و چند کامپوننت پایه‌ی قابل‌استفاده‌ی مجدد (اسلایدر، رنج‌اسلایدر، صفحه‌ی اشباع رنگ).
4
+
5
+ معمولاً مستقیم به این پکیج نیازی ندارید — بقیه‌ی بسته‌ها به‌صورت خودکار بهش وابسته‌ان. ولی اگه دارید یه کامپوننت سفارشی می‌سازید که باید با بقیه‌ی کتابخونه هم‌خونی داشته باشه (دارک‌مود، RTL، درگ‌وپرفورمنس)، از همین ابزارها استفاده کنید.
6
+
7
+ ## نصب
8
+
9
+ ```bash
10
+ npm install ngx-kit
11
+ ```
12
+
13
+ سبک‌های پایه (شامل `color-scheme` که دارک‌مود رو فعال می‌کنه) رو یک‌بار در سراسر اپ ایمپورت کنید:
14
+
15
+ ```scss
16
+ // styles.scss
17
+ @import 'ngx-kit/styles/all.css';
18
+ ```
19
+
20
+ ## سرویس‌ها
21
+
22
+ ### `OverlayService`
23
+
24
+ موتور اصلی پشتِ همه‌ی چیزهای شناور کتابخونه (منو، دیالوگ، پاپ‌آپ‌های رنگ/گرادیان/زاویه). یک المنت انگولاری رو داخل یک `<dialog>` بومیِ مرورگر (`showModal()`) نمایش می‌ده و نسبت به یک anchor موقعیت‌دهی می‌کنه.
25
+
26
+ ```ts
27
+ import { OverlayService } from 'ngx-kit/shared';
28
+
29
+ const overlay = inject(OverlayService);
30
+ const viewContainerRef = inject(ViewContainerRef);
31
+
32
+ const ref = overlay.open({
33
+ component: MyComponent,
34
+ viewContainerRef,
35
+ anchor: buttonElementRef.nativeElement,
36
+ placement: 'bottom', // 'top' | 'bottom' | 'auto'
37
+ alignment: 'start', // 'start' | 'center' | 'end'
38
+ margin: 8,
39
+ });
40
+
41
+ ref.close(); // OverlayRef.close() آرگومان یا afterClosed نداره؛ برای اون‌جور رفتار (نتیجه‌ی بازگشتی، افترکلوز) از ngx-kit/dialog استفاده کنید که روی همین سرویس بنا شده
42
+ ```
43
+
44
+ چیزهایی که به‌صورت خودکار برات مدیریت می‌شه:
45
+
46
+ - **موقعیت‌دهی هوشمند**: اگه فضای کافی پایین anchor نباشه، خودکار بالا می‌ره (`placement:'auto'`).
47
+ - **بستن با کلیک بیرون**: با تشخیص کلیک روی backdrop، نه با listener سراسری روی document.
48
+ - **پشته‌بندی درست**: چند اورلیِ هم‌زمان (مثلاً یه منوی زیرمنو‌دار) درست کار می‌کنن؛ Escape فقط آخرین (بالاترین) اورلی رو می‌بنده.
49
+ - **بازگشتِ فوکوس**: بعد از بسته‌شدن، فوکوس به همون المنتی که قبلش فوکوس داشت برمی‌گرده (دسترس‌پذیری).
50
+ - **RTL خودکار**: alignment و placement بر اساس جهت واقعیِ صفحه (نه فقط یه فرض ثابت) حساب می‌شن.
51
+
52
+ ### `DirectionService`
53
+
54
+ یه سیگنال (`isRtl(): boolean`) که با `MutationObserver` روی attribute-ی `dir` عنصر `<html>` گوش می‌ده و به‌محض تغییرش، ری‌اکتیو آپدیت می‌شه — یعنی اگه اپ شما زبان رو runtime عوض کنه، همه‌چیز خودکار هماهنگ می‌مونه.
55
+
56
+ ```ts
57
+ const direction = inject(DirectionService);
58
+ direction.isRtl(); // signal<boolean>
59
+ ```
60
+
61
+ ### `BrowserService`
62
+
63
+ ```ts
64
+ const browser = inject(BrowserService);
65
+ browser.prefersDarkMode; // boolean — یه‌بار در لحظه‌ی ساخت سرویس خونده می‌شه
66
+ ```
67
+
68
+ ## ابزارهای Utility
69
+
70
+ ### `startDragSession(callbacks)`
71
+
72
+ جایگزینِ الگوی مشکل‌دارِ `@HostListener('document:mousemove', ...)` که listener رو برای کل عمر کامپوننت روی `document` نگه می‌داره (حتی وقتی دراگی در جریان نیست — یه مشکل واقعیِ پرفورمنس روی صفحاتی با چند نمونه‌ی هم‌زمان). این تابع فقط در طول یک درگِ واقعی، listener اضافه می‌کنه و خودش پاک می‌کنه؛ `touchmove` هم با `{passive:false}` مدیریت می‌شه، پس درگ‌کردن روی موبایل صفحه رو اسکرول نمی‌کنه.
73
+
74
+ ```ts
75
+ import { startDragSession } from 'ngx-kit/shared';
76
+
77
+ let stop: (() => void) | undefined;
78
+
79
+ function onPointerDown(ev: MouseEvent | TouchEvent) {
80
+ stop?.();
81
+ stop = startDragSession({
82
+ onMove: (ev) => {
83
+ /* آپدیت موقعیت */
84
+ },
85
+ onEnd: () => {
86
+ stop = undefined;
87
+ },
88
+ });
89
+ }
90
+ ```
91
+
92
+ > اگه کامپوننت‌تون `OnPush` هست و از `startDragSession` (به‌جای `@HostListener`) استفاده می‌کنید، حتماً داخل `onMove`/`onEnd` خودتون `ChangeDetectorRef.markForCheck()` رو صدا بزنید — برخلاف `@HostListener` که خودکار view رو dirty می‌کنه، `addEventListener` دستی این کار رو نمی‌کنه.
93
+
94
+ ### `getOffsetPosition(event, element)`
95
+
96
+ موقعیت pointer/touch رو نسبت به گوشه‌ی بالا-چپِ یه المنت مشخص برمی‌گردونه؛ برای پیاده‌سازیِ کامپوننت‌های درگ‌محور (اسلایدر، انتخاب‌گر رنگ و ...) استفاده می‌شه.
97
+
98
+ ### `mergeConfig(base, override)`
99
+
100
+ ادغام عمیقِ دو آبجکت کانفیگ (برای الگوی `provideXxx({...})` که همه‌ی کتابخونه ازش استفاده می‌کنه).
101
+
102
+ ## کامپوننت‌های پایه
103
+
104
+ اینا رو مستقیم هم می‌شه استفاده کرد، ولی بیشتر به‌عنوان بلوک‌های سازنده‌ی کامپوننت‌های دیگه (مثل `color-picker`, `box-shadow`) طراحی شدن:
105
+
106
+ | کامپوننت | Selector | توضیح |
107
+ | ---------------------- | -------------------- | ------------------------------------------------------------------- |
108
+ | `SliderComponent` | `slider` | اسلایدر تک‌مقداره، `ControlValueAccessor`، `[min]`/`[max]`/`[step]` |
109
+ | `RangeSliderComponent` | `range-slider` | اسلایدر بازه‌ای (دو thumb) |
110
+ | `SaturationComponent` | داخلی (color-picker) | صفحه‌ی دوبعدیِ انتخاب اشباع/روشنایی رنگ |
111
+
112
+ ## دارک‌مود و RTL
113
+
114
+ هر دو مستقیماً روی `ngx-kit/shared` تکیه دارن:
115
+
116
+ - **دارک‌مود**: از تابع CSS بومیِ `light-dark()` استفاده می‌شه. برای این‌که کار کنه، باید `color-scheme: light dark` (یا `only light`/`only dark` برای force کردن دستی) روی `:root` ست بشه — این کار با ایمپورت‌کردن `ngx-kit/styles/all.css` خودکار انجام می‌شه. برای force کردن دستیِ تم (مستقل از `prefers-color-scheme` سیستم)، `data-ngx-theme="dark"` یا `"light"` رو روی `<html>`/`<body>` بذارید.
117
+ - **RTL**: با `dir="rtl"` روی `<html>` فعال می‌شه؛ همه‌جای کتابخونه از CSS logical properties (`inset-inline-start` و ...) استفاده شده، پس نیازی به استایل جداگانه نیست.