ngx-kit 1.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.
@@ -0,0 +1,607 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, EventEmitter, forwardRef, ViewChild, Output, Input, ChangeDetectionStrategy, Component, ElementRef, HostListener, Directive } from '@angular/core';
3
+ import * as i2 from '@angular/forms';
4
+ import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
5
+ import * as i1$1 from 'ngx-input/shared';
6
+ import { BrowserService, RangeSliderComponent } from 'ngx-input/shared';
7
+ import { NgxInputColor } from 'ngx-input/color-picker';
8
+ import { NgxInputAngle } from 'ngx-input/angle-selector';
9
+ import * as i1 from '@angular/common';
10
+ import { CommonModule } from '@angular/common';
11
+
12
+ function buildGradientFromStops(stops, type = 'linear', rotation = 0) {
13
+ if (!stops || stops.length === 0)
14
+ return '';
15
+ // sort by numeric value
16
+ const sorted = [...stops].sort((a, b) => a.value - b.value);
17
+ // clamp 0..100 and format stops
18
+ const parts = sorted.map((s) => {
19
+ const v = Math.max(0, Math.min(Number(s.value) || 0, 100));
20
+ return `${s.color.trim()} ${v}%`;
21
+ });
22
+ let prefix = '';
23
+ if (type === 'linear') {
24
+ // rotation can be number (deg) or string like 'to right' or '45deg'
25
+ if (typeof rotation === 'number')
26
+ prefix = `${rotation}deg, `;
27
+ else if (typeof rotation === 'string' && rotation.trim().length)
28
+ prefix = `${rotation.trim()}, `;
29
+ }
30
+ else if (type === 'radial') {
31
+ // keep simple "circle" default: caller may put 'circle' in rotation (or pass separate option if needed)
32
+ prefix = typeof rotation === 'string' && rotation.trim() ? `${rotation.trim()}, ` : 'circle, ';
33
+ }
34
+ else if (type === 'conic') {
35
+ // conic-gradient accepts angle like 'from 45deg at 50% 50%'
36
+ if (typeof rotation === 'number')
37
+ prefix = `from ${rotation}deg, `;
38
+ else if (typeof rotation === 'string' && rotation.trim())
39
+ prefix = `${rotation.trim()}, `;
40
+ }
41
+ return `${type}-gradient(${prefix}${parts.join(', ')})`;
42
+ }
43
+ function generateRandomColor() {
44
+ const letters = '0123456789ABCDEF';
45
+ let color = '#';
46
+ for (let i = 0; i < 6; i++) {
47
+ color += letters[Math.floor(Math.random() * 16)];
48
+ }
49
+ return color;
50
+ }
51
+ function isValidGradient(value) {
52
+ if (!value || typeof value !== 'string')
53
+ return false;
54
+ return /^\s*(conic|linear|radial)-gradient\s*\(/i.test(value.trim());
55
+ }
56
+ /**
57
+ * parseGradient
58
+ * - returns: { type, rotation (number|string), stops, valid }
59
+ * - stops: array of { id, color, value } where value is 0..100 (percent)
60
+ * - rotation: number (deg) for linear if parsed as angle, or string (e.g. 'to right' or '45deg')
61
+ */
62
+ function parseGradient(value) {
63
+ let type = 'linear';
64
+ let rotation = 180;
65
+ let shape;
66
+ let stops = [];
67
+ let valid = false;
68
+ if (!value)
69
+ return { type, rotation, shape, stops, valid };
70
+ const match = value.trim().match(/^(\s*)(conic|linear|radial)-gradient\s*\((.*)\)$/i);
71
+ if (!match)
72
+ return { type, rotation, shape, stops, valid };
73
+ type = match[2].toLowerCase();
74
+ let content = match[3].trim();
75
+ // --- Split arguments by commas, respecting parentheses (for rgba, hsl, etc.)
76
+ const parts = [];
77
+ let buf = '';
78
+ let depth = 0;
79
+ for (const c of content) {
80
+ if (c === '(')
81
+ depth++;
82
+ if (c === ')')
83
+ depth--;
84
+ if (c === ',' && depth === 0) {
85
+ parts.push(buf.trim());
86
+ buf = '';
87
+ }
88
+ else {
89
+ buf += c;
90
+ }
91
+ }
92
+ if (buf.trim())
93
+ parts.push(buf.trim());
94
+ // --- Determine starting index for color stops
95
+ let colorStopStart = 0;
96
+ const first = parts[0];
97
+ if (type === 'linear') {
98
+ // e.g., "90deg" or "to right"
99
+ const angleMatch = first.match(/^(\d+)(deg)?$/i);
100
+ if (angleMatch) {
101
+ rotation = parseFloat(angleMatch[1]);
102
+ colorStopStart = 1;
103
+ }
104
+ else if (/^to /i.test(first)) {
105
+ // optional direction mapping
106
+ colorStopStart = 1;
107
+ }
108
+ }
109
+ else if (type === 'radial') {
110
+ // e.g., "circle", "circle at center", "ellipse at top left"
111
+ if (!/^#|rgb|hsl|[a-z]+\(/i.test(first)) {
112
+ shape = first;
113
+ colorStopStart = 1;
114
+ }
115
+ }
116
+ else if (type === 'conic') {
117
+ // e.g., "from 0deg at center"
118
+ if (!/^#|rgb|hsl|[a-z]+\(/i.test(first))
119
+ colorStopStart = 1;
120
+ }
121
+ // --- Regex for color stops
122
+ const colorStopRegex = /((#([0-9a-fA-F]{3,8}))|(rgba?\([^\)]+\))|(hsla?\([^\)]+\))|([a-zA-Z]+))(\s+([\d.]+%?))?/;
123
+ for (let i = colorStopStart; i < parts.length; i++) {
124
+ const stopPart = parts[i].trim();
125
+ const m = stopPart.match(colorStopRegex);
126
+ if (m) {
127
+ const color = m[1];
128
+ const posStr = m[9];
129
+ let value = 0;
130
+ if (posStr && posStr.endsWith('%'))
131
+ value = parseFloat(posStr);
132
+ else if (posStr)
133
+ value = parseFloat(posStr);
134
+ else {
135
+ // اگر درصدی وجود نداشت، با توجه به ایندکس مقدار دهی کن
136
+ if (stops.length === 0)
137
+ value = 0;
138
+ else if (i === parts.length - 1)
139
+ value = 100;
140
+ else
141
+ value = (100 / (parts.length - colorStopStart - 1)) * stops.length;
142
+ }
143
+ stops.push({ color, value, id: generateId(stops) });
144
+ }
145
+ }
146
+ valid = stops.length >= 2;
147
+ return { type, rotation, shape, stops, valid };
148
+ }
149
+ function generateId(rangeValues) {
150
+ const id = 'ngx-stop-' + Math.random().toString(36).substring(2, 9);
151
+ return rangeValues.find((x) => x.id === id) ? generateId(rangeValues) : id;
152
+ }
153
+
154
+ const DefaultGradients = [
155
+ // Sunset
156
+ [
157
+ { id: '1', value: 0, color: '#ff7e5f' },
158
+ { id: '2', value: 100, color: '#feb47b' },
159
+ ],
160
+ // Ocean Blue
161
+ [
162
+ { id: '1', value: 0, color: '#00c6ff' },
163
+ { id: '2', value: 100, color: '#0072ff' },
164
+ ],
165
+ // Purple Dream
166
+ [
167
+ { id: '1', value: 0, color: '#a18cd1' },
168
+ { id: '2', value: 100, color: '#fbc2eb' },
169
+ ],
170
+ // Cool Sky
171
+ [
172
+ { id: '1', value: 0, color: '#2193b0' },
173
+ { id: '2', value: 100, color: '#6dd5ed' },
174
+ ],
175
+ // Peach
176
+ [
177
+ { id: '1', value: 0, color: '#ed4264' },
178
+ { id: '2', value: 100, color: '#ffedbc' },
179
+ ],
180
+ // Night Fade
181
+ [
182
+ { id: '1', value: 0, color: '#a18cd1' },
183
+ { id: '2', value: 100, color: '#fbc2eb' },
184
+ ],
185
+ // Aqua Marine
186
+ [
187
+ { id: '1', value: 0, color: '#1a2980' },
188
+ { id: '2', value: 100, color: '#26d0ce' },
189
+ ],
190
+ // Forest
191
+ [
192
+ { id: '1', value: 0, color: '#5a3f37' },
193
+ { id: '2', value: 100, color: '#2c7744' },
194
+ ],
195
+ // Flame
196
+ [
197
+ { id: '1', value: 0, color: '#ff4e50' },
198
+ { id: '2', value: 100, color: '#f9d423' },
199
+ ],
200
+ // Blue Lagoon
201
+ [
202
+ { id: '1', value: 0, color: '#43cea2' },
203
+ { id: '2', value: 100, color: '#185a9d' },
204
+ ],
205
+ // Retro
206
+ [
207
+ { id: '1', value: 0, color: '#3fada8' },
208
+ { id: '2', value: 100, color: '#808080' },
209
+ ],
210
+ // Sunrise
211
+ [
212
+ { id: '1', value: 0, color: '#ff512f' },
213
+ { id: '2', value: 100, color: '#dd2476' },
214
+ ],
215
+ // Rainbow
216
+ [
217
+ { id: '1', value: 0, color: '#ff0000' },
218
+ { id: '2', value: 20, color: '#ff9900' },
219
+ { id: '3', value: 40, color: '#ffff00' },
220
+ { id: '4', value: 60, color: '#00ff00' },
221
+ { id: '5', value: 80, color: '#0000ff' },
222
+ { id: '6', value: 100, color: '#8b00ff' },
223
+ ],
224
+ // Candy
225
+ [
226
+ { id: '1', value: 0, color: '#f953c6' },
227
+ { id: '2', value: 100, color: '#b91d73' },
228
+ ],
229
+ // Citrus
230
+ [
231
+ { id: '1', value: 0, color: '#fdc830' },
232
+ { id: '2', value: 100, color: '#f37335' },
233
+ ],
234
+ // Lava
235
+ [
236
+ { id: '1', value: 0, color: '#e52d27' },
237
+ { id: '2', value: 100, color: '#b31217' },
238
+ ],
239
+ // Winter
240
+ [
241
+ { id: '1', value: 0, color: '#e6dada' },
242
+ { id: '2', value: 100, color: '#274046' },
243
+ ],
244
+ // Purple Love
245
+ [
246
+ { id: '1', value: 0, color: '#cc2b5e' },
247
+ { id: '2', value: 100, color: '#753a88' },
248
+ ],
249
+ // Mint
250
+ [
251
+ { id: '1', value: 0, color: '#76b852' },
252
+ { id: '2', value: 100, color: '#8dc26f' },
253
+ ],
254
+ // Cloud
255
+ [
256
+ { id: '1', value: 0, color: '#bdc3c7' },
257
+ { id: '2', value: 100, color: '#2c3e50' },
258
+ ],
259
+ ];
260
+
261
+ class NgxInputGradientComponent {
262
+ cd;
263
+ browserService = inject(BrowserService);
264
+ theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
265
+ set setTheme(val) {
266
+ if (!val || val == 'auto') {
267
+ this.theme = this.browserService.prefersDarkMode ? 'dark' : 'light';
268
+ }
269
+ else {
270
+ this.theme = val;
271
+ }
272
+ }
273
+ change = new EventEmitter();
274
+ defaultGradients = [];
275
+ resultGradient = '';
276
+ baseBg = '';
277
+ rangeValues = [];
278
+ type = 'linear';
279
+ rotation = 90;
280
+ selectedIndex = 0;
281
+ isDisabled = false;
282
+ _onChange = (value) => { };
283
+ _onTouched = () => { };
284
+ _onValidateChange = () => { };
285
+ rangeSlider;
286
+ constructor(cd) {
287
+ this.cd = cd;
288
+ }
289
+ ngOnInit() {
290
+ this.setDefaultGradients();
291
+ }
292
+ ngOnDestroy() { }
293
+ registerOnChange(fn) {
294
+ this._onChange = fn;
295
+ }
296
+ registerOnTouched(fn) {
297
+ this._onTouched = fn;
298
+ }
299
+ setDisabledState(disabled) {
300
+ this.isDisabled = disabled;
301
+ }
302
+ registerOnValidatorChange(fn) {
303
+ this._onValidateChange = fn;
304
+ }
305
+ validate(control) {
306
+ if (!this.resultGradient)
307
+ return { required: true };
308
+ const parsed = parseGradient(this.resultGradient);
309
+ if (!parsed.valid)
310
+ return { invalid: true };
311
+ if (parsed.stops.length < 2)
312
+ return { stops: 'at least 2 color stops required' };
313
+ return null;
314
+ }
315
+ writeValue(value) {
316
+ if (value && isValidGradient(value)) {
317
+ const parsed = parseGradient(value);
318
+ if (parsed.valid) {
319
+ this.resultGradient = value;
320
+ this.type = parsed.type;
321
+ this.rotation = +parsed.rotation;
322
+ this.rangeValues = parsed.stops;
323
+ }
324
+ else {
325
+ this.resultGradient = '';
326
+ this.rangeValues = [
327
+ { color: generateRandomColor(), value: 0, id: this.generateId() },
328
+ { color: generateRandomColor(), value: 100, id: this.generateId() },
329
+ ];
330
+ this.type = 'linear';
331
+ this.rotation = 90;
332
+ }
333
+ }
334
+ else {
335
+ this.resultGradient = '';
336
+ this.rangeValues = [
337
+ { color: generateRandomColor(), value: 0, id: this.generateId() },
338
+ { color: generateRandomColor(), value: 100, id: this.generateId() },
339
+ ];
340
+ this.type = 'linear';
341
+ this.rotation = 90;
342
+ }
343
+ this.generateGradient();
344
+ }
345
+ generateId() {
346
+ let id = 'ngx-thumb-' + Math.random().toString(36).substring(2, 9);
347
+ if (this.rangeValues.findIndex((x) => x.id == id) >= 0) {
348
+ return this.generateId();
349
+ }
350
+ return id;
351
+ }
352
+ stopPropagation(ev) {
353
+ ev.stopPropagation();
354
+ }
355
+ remove() {
356
+ if (this.rangeValues.length > 2) {
357
+ this.rangeValues.splice(this.selectedIndex, 1);
358
+ this.selectedIndex = 0;
359
+ this.generateGradient();
360
+ }
361
+ }
362
+ generateGradient(ev) {
363
+ if (ev && this.rangeValues[this.selectedIndex]) {
364
+ this.rangeValues[this.selectedIndex].color = ev;
365
+ }
366
+ for (let item of this.rangeValues) {
367
+ item.color ??= generateRandomColor();
368
+ }
369
+ this.baseBg = buildGradientFromStops(this.rangeValues, 'linear', 90);
370
+ this.resultGradient = buildGradientFromStops(this.rangeValues, this.type, +this.rotation);
371
+ this.emitChange();
372
+ }
373
+ updateRangeSlider() {
374
+ if (this.rangeSlider) {
375
+ this.rangeSlider.writeValue(this.rangeValues);
376
+ }
377
+ }
378
+ emitChange() {
379
+ this._onChange(this.resultGradient);
380
+ this.change.emit(this.resultGradient);
381
+ }
382
+ setDefaultGradients() {
383
+ this.defaultGradients = [];
384
+ for (let item of DefaultGradients) {
385
+ this.defaultGradients.push(buildGradientFromStops(item, 'linear', 90));
386
+ }
387
+ }
388
+ onSelectDefault(item, i) {
389
+ // console.log('onSelectDefault', item, i);
390
+ this.writeValue(item);
391
+ this.emitChange();
392
+ }
393
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputGradientComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.4", type: NgxInputGradientComponent, isStandalone: true, selector: "ngx-input-gradient", inputs: { setTheme: ["theme", "setTheme"] }, outputs: { change: "change" }, host: { properties: { "class.dark": "theme==\"dark\"" } }, providers: [
395
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputGradientComponent), multi: true },
396
+ {
397
+ provide: NG_VALIDATORS,
398
+ multi: true,
399
+ useExisting: NgxInputGradientComponent,
400
+ },
401
+ ], viewQueries: [{ propertyName: "rangeSlider", first: true, predicate: ["rangeSlider"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"ngx-input-gradient-picker\" (click)=\"stopPropagation($event)\">\r\n <div class=\"ngx-color-preview\" [ngStyle]=\"{ '--ngx-selected-gradient': resultGradient }\"></div>\r\n <div class=\"ngx-c-inner\">\r\n <range-slider\r\n [(ngModel)]=\"rangeValues\"\r\n name=\"rangeCalues\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [step]=\"1\"\r\n [addNewRangeOnClick]=\"true\"\r\n [background]=\"baseBg\"\r\n [(selectedIndex)]=\"selectedIndex\"\r\n (change)=\"generateGradient()\"\r\n #rangeSlider></range-slider>\r\n\r\n <div class=\"text-end\">\r\n <button class=\"remove-btn\" type=\"button\" (click)=\"remove()\">remove</button>\r\n </div>\r\n @if (rangeValues[selectedIndex]) {\r\n <div class=\"ngx-row\">\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Color</div>\r\n <div class=\"input-color\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"rangeValues[selectedIndex].color\"\r\n name=\"color\"\r\n #inputColor\r\n (ngModelChange)=\"generateGradient(); updateRangeSlider()\" />\r\n <span\r\n #ngxGradColor\r\n class=\"color\"\r\n [style.backgroundColor]=\"rangeValues[selectedIndex].color\"\r\n [ngxInputColor]=\"inputColor\"\r\n [theme]=\"theme\"\r\n [ngModel]=\"rangeValues[selectedIndex].color\"\r\n [simpleMode]=\"true\"\r\n (change)=\"generateGradient($event)\"></span>\r\n </div>\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Position</div>\r\n <input\r\n type=\"number\"\r\n [(ngModel)]=\"rangeValues[selectedIndex].value\"\r\n min=\"0\"\r\n max=\"100\"\r\n name=\"posiition\"\r\n (change)=\"generateGradient(); updateRangeSlider()\" />\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Rotation</div>\r\n <div class=\"ngx-input-group\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"rotation\"\r\n ngxInputAngle\r\n [theme]=\"theme\"\r\n (change)=\"generateGradient()\"\r\n name=\"rotation\"\r\n [disabled]=\"type == 'radial'\" />\r\n <span class=\"ngx-input-prefix\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\r\n <path\r\n d=\"M360.5 217.5l-152 143.1C203.9 365.8 197.9 368 192 368s-11.88-2.188-16.5-6.562L23.5 217.5C13.87 208.3 13.47 193.1 22.56 183.5C31.69 173.8 46.94 173.5 56.5 182.6L192 310.9l135.5-128.4c9.562-9.094 24.75-8.75 33.94 .9375C370.5 193.1 370.1 208.3 360.5 217.5z\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Type</div>\r\n <div class=\"ngx-input-group\">\r\n <select [(ngModel)]=\"type\" (change)=\"generateGradient()\" name=\"type\">\r\n <option value=\"linear\">linear</option>\r\n <option value=\"radial\">radial</option>\r\n </select>\r\n <span class=\"ngx-input-prefix\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\r\n <path\r\n d=\"M360.5 217.5l-152 143.1C203.9 365.8 197.9 368 192 368s-11.88-2.188-16.5-6.562L23.5 217.5C13.87 208.3 13.47 193.1 22.56 183.5C31.69 173.8 46.94 173.5 56.5 182.6L192 310.9l135.5-128.4c9.562-9.094 24.75-8.75 33.94 .9375C370.5 193.1 370.1 208.3 360.5 217.5z\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"default-list\">\r\n @for (item of defaultGradients; track $index; let i = $index) {\r\n <span [style.background]=\"item\" (click)=\"onSelectDefault(item, i)\"></span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff}.ngx-input-gradient-picker{width:270px;max-width:100%;border:1px #bfbfbf solid;border-radius:15px;background:var(--ngx-color-bg);color:var(--ngx-color-text);overflow:hidden;box-shadow:0 0 20px #0000004f;direction:ltr;font-family:arial,tahoma}.ngx-input-gradient-picker .ngx-c-inner{padding:0 12px 12px}.ngx-input-gradient-picker *{box-sizing:border-box}.ngx-color-preview{min-height:100px;padding:10px 36px;line-height:1.6;font-size:14px;font-family:arial,tahoma;font-weight:700;position:relative;color:#353535;background-color:#fff}.ngx-color-preview.is-dark-color{color:#fff}.ngx-color-preview:after,.ngx-color-preview:before{content:\" \";position:absolute;inset:0}.ngx-color-preview:before{background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-color-preview:after{background:var(--ngx-selected-gradient)}.ngx-row{display:flex;flex-wrap:wrap;gap:12px}.ngx-row .ngx-col-6{width:47%}.ngx-row .ngx-input-group{display:flex}.ngx-row .ngx-input-group .ngx-input-prefix{width:14px;margin-left:-28px;margin-top:6px;pointer-events:none}.ngx-row .ngx-input-group .ngx-input-prefix svg{max-width:100%;max-height:100%;fill:var(--ngx-color-text)}.ngx-row .input-color{position:relative}.ngx-row .input-color input{padding-right:26px}.ngx-row .input-color .color{position:absolute;top:4px;right:5px;cursor:pointer;display:inline-block;width:24px;height:24px;border-radius:4px;border:1px solid #ccc;transition:all .3s}.ngx-row .input-color .color:hover{border-color:#8db6e4}.ngx-row select,.ngx-row input{outline:none;border:1px solid #ececec;border-radius:4px;padding:8px 10px;background:none;width:100%;color:var(--ngx-color-text);appearance:none}.ngx-row select option,.ngx-row input option{padding:10px 20px;background-color:#fff;transition:all .3s;background:var(--ngx-color-bg);color:var(--ngx-color-text)}.ngx-row select option:hover,.ngx-row input option:hover{background:#f0f0f0}.text-end{text-align:end}.remove-btn{background:none;border:none;outline:none;color:#07f;transition:color .3s}.remove-btn:hover{color:#0462cc}.default-list{display:flex;gap:6px;flex-wrap:wrap;margin:16px 0}.default-list span{width:36px;height:26px;border-radius:4px;cursor:pointer;transition:transform .3s}.default-list span:hover{transform:scale(1.2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number]:not([ngNoCva])[formControlName],input[type=number]:not([ngNoCva])[formControl],input[type=number]:not([ngNoCva])[ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple]):not([ngNoCva])[formControlName],select:not([multiple]):not([ngNoCva])[formControl],select:not([multiple]):not([ngNoCva])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: RangeSliderComponent, selector: "range-slider", inputs: ["step", "min", "max", "background", "isBgTransparent", "addNewRangeOnClick", "selectedIndex"], outputs: ["change", "selectedIndexChange"] }, { kind: "directive", type: NgxInputColor, selector: "[ngxInputColor]", inputs: ["setInputBackgroundColor", "defaultInspector", "simpleMode", "outputType", "theme", "useAlphaChannel", "ngxInputColor"], outputs: ["change"] }, { kind: "directive", type: NgxInputAngle, selector: "[ngxInputAngle]", inputs: ["theme", "size", "openOnCLick"], outputs: ["change"], exportAs: ["ngxInputAngle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
402
+ }
403
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputGradientComponent, decorators: [{
404
+ type: Component,
405
+ args: [{ selector: 'ngx-input-gradient', changeDetection: ChangeDetectionStrategy.OnPush, providers: [
406
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputGradientComponent), multi: true },
407
+ {
408
+ provide: NG_VALIDATORS,
409
+ multi: true,
410
+ useExisting: NgxInputGradientComponent,
411
+ },
412
+ ], host: {
413
+ '[class.dark]': 'theme=="dark"',
414
+ }, imports: [CommonModule, FormsModule, RangeSliderComponent, NgxInputColor, NgxInputAngle], template: "<div class=\"ngx-input-gradient-picker\" (click)=\"stopPropagation($event)\">\r\n <div class=\"ngx-color-preview\" [ngStyle]=\"{ '--ngx-selected-gradient': resultGradient }\"></div>\r\n <div class=\"ngx-c-inner\">\r\n <range-slider\r\n [(ngModel)]=\"rangeValues\"\r\n name=\"rangeCalues\"\r\n [min]=\"0\"\r\n [max]=\"100\"\r\n [step]=\"1\"\r\n [addNewRangeOnClick]=\"true\"\r\n [background]=\"baseBg\"\r\n [(selectedIndex)]=\"selectedIndex\"\r\n (change)=\"generateGradient()\"\r\n #rangeSlider></range-slider>\r\n\r\n <div class=\"text-end\">\r\n <button class=\"remove-btn\" type=\"button\" (click)=\"remove()\">remove</button>\r\n </div>\r\n @if (rangeValues[selectedIndex]) {\r\n <div class=\"ngx-row\">\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Color</div>\r\n <div class=\"input-color\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"rangeValues[selectedIndex].color\"\r\n name=\"color\"\r\n #inputColor\r\n (ngModelChange)=\"generateGradient(); updateRangeSlider()\" />\r\n <span\r\n #ngxGradColor\r\n class=\"color\"\r\n [style.backgroundColor]=\"rangeValues[selectedIndex].color\"\r\n [ngxInputColor]=\"inputColor\"\r\n [theme]=\"theme\"\r\n [ngModel]=\"rangeValues[selectedIndex].color\"\r\n [simpleMode]=\"true\"\r\n (change)=\"generateGradient($event)\"></span>\r\n </div>\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Position</div>\r\n <input\r\n type=\"number\"\r\n [(ngModel)]=\"rangeValues[selectedIndex].value\"\r\n min=\"0\"\r\n max=\"100\"\r\n name=\"posiition\"\r\n (change)=\"generateGradient(); updateRangeSlider()\" />\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Rotation</div>\r\n <div class=\"ngx-input-group\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"rotation\"\r\n ngxInputAngle\r\n [theme]=\"theme\"\r\n (change)=\"generateGradient()\"\r\n name=\"rotation\"\r\n [disabled]=\"type == 'radial'\" />\r\n <span class=\"ngx-input-prefix\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\r\n <path\r\n d=\"M360.5 217.5l-152 143.1C203.9 365.8 197.9 368 192 368s-11.88-2.188-16.5-6.562L23.5 217.5C13.87 208.3 13.47 193.1 22.56 183.5C31.69 173.8 46.94 173.5 56.5 182.6L192 310.9l135.5-128.4c9.562-9.094 24.75-8.75 33.94 .9375C370.5 193.1 370.1 208.3 360.5 217.5z\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n <div class=\"ngx-col-6\">\r\n <div class=\"label\">Type</div>\r\n <div class=\"ngx-input-group\">\r\n <select [(ngModel)]=\"type\" (change)=\"generateGradient()\" name=\"type\">\r\n <option value=\"linear\">linear</option>\r\n <option value=\"radial\">radial</option>\r\n </select>\r\n <span class=\"ngx-input-prefix\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\r\n <path\r\n d=\"M360.5 217.5l-152 143.1C203.9 365.8 197.9 368 192 368s-11.88-2.188-16.5-6.562L23.5 217.5C13.87 208.3 13.47 193.1 22.56 183.5C31.69 173.8 46.94 173.5 56.5 182.6L192 310.9l135.5-128.4c9.562-9.094 24.75-8.75 33.94 .9375C370.5 193.1 370.1 208.3 360.5 217.5z\" />\r\n </svg>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"default-list\">\r\n @for (item of defaultGradients; track $index; let i = $index) {\r\n <span [style.background]=\"item\" (click)=\"onSelectDefault(item, i)\"></span>\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [":host{--ngx-color-bg: #fff;--ngx-color-text: #000}:host-context(.dark){--ngx-color-bg: #222;--ngx-color-text: #fff}.ngx-input-gradient-picker{width:270px;max-width:100%;border:1px #bfbfbf solid;border-radius:15px;background:var(--ngx-color-bg);color:var(--ngx-color-text);overflow:hidden;box-shadow:0 0 20px #0000004f;direction:ltr;font-family:arial,tahoma}.ngx-input-gradient-picker .ngx-c-inner{padding:0 12px 12px}.ngx-input-gradient-picker *{box-sizing:border-box}.ngx-color-preview{min-height:100px;padding:10px 36px;line-height:1.6;font-size:14px;font-family:arial,tahoma;font-weight:700;position:relative;color:#353535;background-color:#fff}.ngx-color-preview.is-dark-color{color:#fff}.ngx-color-preview:after,.ngx-color-preview:before{content:\" \";position:absolute;inset:0}.ngx-color-preview:before{background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:16px 16px;background-position:0 0,0 8px,8px -8px,-8px 0px}.ngx-color-preview:after{background:var(--ngx-selected-gradient)}.ngx-row{display:flex;flex-wrap:wrap;gap:12px}.ngx-row .ngx-col-6{width:47%}.ngx-row .ngx-input-group{display:flex}.ngx-row .ngx-input-group .ngx-input-prefix{width:14px;margin-left:-28px;margin-top:6px;pointer-events:none}.ngx-row .ngx-input-group .ngx-input-prefix svg{max-width:100%;max-height:100%;fill:var(--ngx-color-text)}.ngx-row .input-color{position:relative}.ngx-row .input-color input{padding-right:26px}.ngx-row .input-color .color{position:absolute;top:4px;right:5px;cursor:pointer;display:inline-block;width:24px;height:24px;border-radius:4px;border:1px solid #ccc;transition:all .3s}.ngx-row .input-color .color:hover{border-color:#8db6e4}.ngx-row select,.ngx-row input{outline:none;border:1px solid #ececec;border-radius:4px;padding:8px 10px;background:none;width:100%;color:var(--ngx-color-text);appearance:none}.ngx-row select option,.ngx-row input option{padding:10px 20px;background-color:#fff;transition:all .3s;background:var(--ngx-color-bg);color:var(--ngx-color-text)}.ngx-row select option:hover,.ngx-row input option:hover{background:#f0f0f0}.text-end{text-align:end}.remove-btn{background:none;border:none;outline:none;color:#07f;transition:color .3s}.remove-btn:hover{color:#0462cc}.default-list{display:flex;gap:6px;flex-wrap:wrap;margin:16px 0}.default-list span{width:36px;height:26px;border-radius:4px;cursor:pointer;transition:transform .3s}.default-list span:hover{transform:scale(1.2)}\n"] }]
415
+ }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { setTheme: [{
416
+ type: Input,
417
+ args: ['theme']
418
+ }], change: [{
419
+ type: Output
420
+ }], rangeSlider: [{
421
+ type: ViewChild,
422
+ args: ['rangeSlider', { static: true }]
423
+ }] } });
424
+
425
+ class NgxInputGradient {
426
+ el;
427
+ renderer;
428
+ viewContainerRef;
429
+ dialogService;
430
+ setInputBackground = true;
431
+ theme = 'auto';
432
+ _targetInput;
433
+ set ngxInputColor(el) {
434
+ this.isHostInput = false;
435
+ if (el instanceof ElementRef) {
436
+ this._targetInput = el.nativeElement;
437
+ }
438
+ else if (el instanceof HTMLInputElement) {
439
+ this.isHostInput = true;
440
+ this._targetInput = el;
441
+ }
442
+ else {
443
+ this._targetInput = undefined;
444
+ }
445
+ if (this._targetInput) {
446
+ this._targetInput.removeEventListener('input', this.boundInputHandler);
447
+ this._targetInput.addEventListener('input', this.boundInputHandler);
448
+ }
449
+ }
450
+ change = new EventEmitter();
451
+ boundInputHandler = (e) => {
452
+ this.writeValue(e.target.value);
453
+ };
454
+ isHostInput = false;
455
+ pickerRef;
456
+ value = '';
457
+ _onChange = (value) => { };
458
+ _onTouched = () => { };
459
+ _onValidateChange = () => { };
460
+ constructor(el, renderer, viewContainerRef, dialogService) {
461
+ this.el = el;
462
+ this.renderer = renderer;
463
+ this.viewContainerRef = viewContainerRef;
464
+ this.dialogService = dialogService;
465
+ }
466
+ onClick(ev) {
467
+ ev.stopPropagation();
468
+ ev.preventDefault();
469
+ this.toggleColorPicker();
470
+ }
471
+ ngAfterViewInit() {
472
+ if (this._targetInput && this._targetInput.tagName.toLowerCase() === 'input') {
473
+ this.writeValue(this._targetInput.value);
474
+ }
475
+ }
476
+ registerOnChange(fn) {
477
+ this._onChange = fn;
478
+ }
479
+ registerOnTouched(fn) {
480
+ this._onTouched = fn;
481
+ }
482
+ setDisabledState(disabled) {
483
+ if (disabled) {
484
+ this.renderer.setProperty(this.el.nativeElement, 'disabled', disabled);
485
+ }
486
+ else {
487
+ this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
488
+ }
489
+ }
490
+ registerOnValidatorChange(fn) {
491
+ this._onValidateChange = fn;
492
+ }
493
+ validate(control) {
494
+ return null;
495
+ }
496
+ ngOnDestroy() {
497
+ this.destroyPicker();
498
+ }
499
+ writeValue(val) {
500
+ this.value = val;
501
+ if (val && isValidGradient(val)) {
502
+ // const parsed = parseGradient(val);
503
+ if (this.setInputBackground) {
504
+ this.renderer.setStyle(this.el.nativeElement, 'background', val);
505
+ }
506
+ if (this.isHostInput) {
507
+ this.el.nativeElement.value = this.value;
508
+ }
509
+ this._onValidateChange();
510
+ }
511
+ else {
512
+ this.renderer.setStyle(this.el.nativeElement, 'background', '');
513
+ }
514
+ }
515
+ toggleColorPicker() {
516
+ if (this.pickerRef) {
517
+ this.destroyPicker();
518
+ return;
519
+ }
520
+ this.pickerRef = this.dialogService.open({
521
+ anchor: this.el.nativeElement,
522
+ component: NgxInputGradientComponent,
523
+ viewContainerRef: this.viewContainerRef,
524
+ alignment: 'start',
525
+ placement: 'auto',
526
+ configure: (instance, ref) => {
527
+ instance.setTheme = this.theme;
528
+ instance.writeValue(this.value);
529
+ instance.change.subscribe((c) => {
530
+ this.value = c;
531
+ this.emitChange(c);
532
+ });
533
+ // instance.closed.subscribe(() => ref.close());
534
+ },
535
+ onClosed: () => {
536
+ this.pickerRef = undefined;
537
+ },
538
+ });
539
+ }
540
+ destroyPicker() {
541
+ if (this.pickerRef) {
542
+ this.pickerRef.close();
543
+ this.pickerRef = undefined;
544
+ }
545
+ }
546
+ async emitChange(c) {
547
+ if (this.setInputBackground) {
548
+ this.renderer.setStyle(this.el.nativeElement, 'background', c);
549
+ }
550
+ // اگر روی input باشیم، مقدار رو در input قرار بده
551
+ if (this.isHostInput) {
552
+ const input = this.el.nativeElement;
553
+ input.value = c;
554
+ }
555
+ // اگر targetInput وجود داره، در اونم مقدار ست کن
556
+ if (this._targetInput instanceof HTMLInputElement) {
557
+ this._targetInput.value = c;
558
+ const event = new Event('input', { bubbles: true });
559
+ this._targetInput.dispatchEvent(event);
560
+ }
561
+ this._onChange(c);
562
+ this.change.emit(c);
563
+ this._onTouched();
564
+ }
565
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputGradient, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ViewContainerRef }, { token: i1$1.DialogService }], target: i0.ɵɵFactoryTarget.Directive });
566
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.0.4", type: NgxInputGradient, isStandalone: true, selector: "[ngxInputGradient]", inputs: { setInputBackground: "setInputBackground", theme: "theme", ngxInputColor: "ngxInputColor" }, outputs: { change: "change" }, host: { listeners: { "click": "onClick($event)" } }, providers: [
567
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputGradient), multi: true },
568
+ {
569
+ provide: NG_VALIDATORS,
570
+ multi: true,
571
+ useExisting: NgxInputGradient,
572
+ },
573
+ ], ngImport: i0 });
574
+ }
575
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.4", ngImport: i0, type: NgxInputGradient, decorators: [{
576
+ type: Directive,
577
+ args: [{
578
+ selector: '[ngxInputGradient]',
579
+ providers: [
580
+ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxInputGradient), multi: true },
581
+ {
582
+ provide: NG_VALIDATORS,
583
+ multi: true,
584
+ useExisting: NgxInputGradient,
585
+ },
586
+ ],
587
+ }]
588
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ViewContainerRef }, { type: i1$1.DialogService }], propDecorators: { setInputBackground: [{
589
+ type: Input
590
+ }], theme: [{
591
+ type: Input
592
+ }], ngxInputColor: [{
593
+ type: Input,
594
+ args: ['ngxInputColor']
595
+ }], change: [{
596
+ type: Output
597
+ }], onClick: [{
598
+ type: HostListener,
599
+ args: ['click', ['$event']]
600
+ }] } });
601
+
602
+ /**
603
+ * Generated bundle index. Do not edit.
604
+ */
605
+
606
+ export { NgxInputGradient, NgxInputGradientComponent };
607
+ //# sourceMappingURL=ngx-input-gradient-picker.mjs.map