@hakumi-dev/hakumi-components 0.1.18-pre → 0.1.19-pre
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -381
- package/app/javascript/hakumi_components/controllers/hakumi/admin_panel_controller.js +5 -7
- package/app/javascript/hakumi_components/controllers/hakumi/back_top_controller.js +1 -1
- package/app/javascript/hakumi_components/controllers/hakumi/button_controller.js +108 -2
- package/app/javascript/hakumi_components/controllers/hakumi/calendar_controller.js +183 -95
- package/app/javascript/hakumi_components/controllers/hakumi/color_picker_controller.js +23 -285
- package/app/javascript/hakumi_components/controllers/hakumi/date_picker_controller.js +274 -262
- package/app/javascript/hakumi_components/controllers/hakumi/float_button_group_controller.js +2 -2
- package/app/javascript/hakumi_components/controllers/hakumi/message_controller.js +4 -2
- package/app/javascript/hakumi_components/controllers/hakumi/modal_controller.js +119 -125
- package/app/javascript/hakumi_components/controllers/hakumi/table/editable.js +291 -0
- package/app/javascript/hakumi_components/controllers/hakumi/table_controller.js +166 -366
- package/app/javascript/hakumi_components/controllers/hakumi/tabs_controller.js +8 -2
- package/app/javascript/hakumi_components/controllers/hakumi/tag_controller.js +27 -25
- package/app/javascript/hakumi_components/controllers/hakumi/tag_group_controller.js +19 -18
- package/app/javascript/hakumi_components/controllers/hakumi/theme_controller.js +116 -117
- package/app/javascript/hakumi_components/controllers/hakumi/transfer_controller.js +17 -1
- package/app/javascript/hakumi_components/controllers/hakumi/tree_controller.js +363 -78
- package/app/javascript/hakumi_components/controllers/hakumi/typography_controller.js +3 -3
- package/app/javascript/hakumi_components/controllers/hakumi/upload_controller.js +320 -204
- package/app/javascript/hakumi_components/core/render_component.js +37 -11
- package/app/javascript/hakumi_components/utils/color_helper.js +262 -0
- package/app/javascript/stylesheets/_base.scss +9 -0
- package/app/javascript/stylesheets/_hakumi_components.scss +1 -0
- package/app/javascript/stylesheets/components/_breadcrumb.scss +2 -2
- package/app/javascript/stylesheets/components/_calendar.scss +13 -13
- package/app/javascript/stylesheets/components/_cascader.scss +5 -5
- package/app/javascript/stylesheets/components/_checkbox.scss +9 -11
- package/app/javascript/stylesheets/components/_color_picker.scss +11 -11
- package/app/javascript/stylesheets/components/_date_picker.scss +4 -4
- package/app/javascript/stylesheets/components/_descriptions.scss +2 -2
- package/app/javascript/stylesheets/components/_drawer.scss +3 -3
- package/app/javascript/stylesheets/components/_dropdown.scss +2 -2
- package/app/javascript/stylesheets/components/_flex.scss +1 -1
- package/app/javascript/stylesheets/components/_float_button.scss +5 -5
- package/app/javascript/stylesheets/components/_form_item.scss +92 -0
- package/app/javascript/stylesheets/components/_image.scss +15 -15
- package/app/javascript/stylesheets/components/_input.scss +23 -113
- package/app/javascript/stylesheets/components/_layout.scss +27 -26
- package/app/javascript/stylesheets/components/_menu.scss +15 -15
- package/app/javascript/stylesheets/components/_modal.scss +13 -13
- package/app/javascript/stylesheets/components/_notification.scss +3 -3
- package/app/javascript/stylesheets/components/_popover.scss +1 -1
- package/app/javascript/stylesheets/components/_segmented.scss +3 -3
- package/app/javascript/stylesheets/components/_select.scss +6 -6
- package/app/javascript/stylesheets/components/_slider.scss +1 -1
- package/app/javascript/stylesheets/components/_spin.scss +2 -2
- package/app/javascript/stylesheets/components/_steps.scss +10 -10
- package/app/javascript/stylesheets/components/_switch.scss +11 -10
- package/app/javascript/stylesheets/components/_table.scss +6 -6
- package/app/javascript/stylesheets/components/_tag.scss +2 -2
- package/app/javascript/stylesheets/components/_tooltip.scss +4 -4
- package/app/javascript/stylesheets/components/_tree_select.scss +3 -3
- package/app/javascript/stylesheets/components/_typography.scss +3 -3
- package/app/javascript/stylesheets/components/_upload.scss +4 -4
- package/package.json +2 -2
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import RegistryController from "../base/registry_controller.js"
|
|
2
|
+
import {
|
|
3
|
+
defaultHsv,
|
|
4
|
+
extractAlpha,
|
|
5
|
+
formatHsvColor,
|
|
6
|
+
hsvToRgb,
|
|
7
|
+
isValidColor,
|
|
8
|
+
parseColorToHsv
|
|
9
|
+
} from "../../utils/color_helper.js"
|
|
2
10
|
|
|
3
11
|
export default class extends RegistryController {
|
|
4
12
|
static targets = [
|
|
@@ -38,8 +46,8 @@ export default class extends RegistryController {
|
|
|
38
46
|
|
|
39
47
|
// Initialize color from value or default
|
|
40
48
|
const initialColor = this.valueValue || this.defaultValueValue || "#1677ff"
|
|
41
|
-
this.hsv =
|
|
42
|
-
this.alpha =
|
|
49
|
+
this.hsv = parseColorToHsv(initialColor)
|
|
50
|
+
this.alpha = extractAlpha(initialColor)
|
|
43
51
|
|
|
44
52
|
// Bind handlers
|
|
45
53
|
this.boundOutsideClick = this.handleOutsideClick.bind(this)
|
|
@@ -142,7 +150,7 @@ export default class extends RegistryController {
|
|
|
142
150
|
if (event) event.stopPropagation()
|
|
143
151
|
if (this.disabledValue) return
|
|
144
152
|
|
|
145
|
-
this.hsv =
|
|
153
|
+
this.hsv = defaultHsv()
|
|
146
154
|
this.alpha = 1
|
|
147
155
|
this.updateUI()
|
|
148
156
|
this.updateHiddenInput("")
|
|
@@ -152,8 +160,8 @@ export default class extends RegistryController {
|
|
|
152
160
|
setValue(value) {
|
|
153
161
|
if (this.disabledValue) return
|
|
154
162
|
|
|
155
|
-
this.hsv =
|
|
156
|
-
this.alpha =
|
|
163
|
+
this.hsv = parseColorToHsv(value)
|
|
164
|
+
this.alpha = extractAlpha(value)
|
|
157
165
|
this.updateUI()
|
|
158
166
|
this.updateHiddenInput(value)
|
|
159
167
|
this.dispatchEvent("change", { value, hsv: this.hsv, alpha: this.alpha })
|
|
@@ -292,7 +300,7 @@ export default class extends RegistryController {
|
|
|
292
300
|
handleColorInput(event) {
|
|
293
301
|
// Real-time input - don't update yet, just validate
|
|
294
302
|
const value = event.target.value
|
|
295
|
-
if (
|
|
303
|
+
if (isValidColor(value)) {
|
|
296
304
|
event.target.classList.remove("hakumi-color-picker-input-invalid")
|
|
297
305
|
} else {
|
|
298
306
|
event.target.classList.add("hakumi-color-picker-input-invalid")
|
|
@@ -302,9 +310,9 @@ export default class extends RegistryController {
|
|
|
302
310
|
handleColorInputChange(event) {
|
|
303
311
|
const value = event.target.value
|
|
304
312
|
|
|
305
|
-
if (
|
|
306
|
-
this.hsv =
|
|
307
|
-
this.alpha =
|
|
313
|
+
if (isValidColor(value)) {
|
|
314
|
+
this.hsv = parseColorToHsv(value)
|
|
315
|
+
this.alpha = extractAlpha(value)
|
|
308
316
|
this.updateUI()
|
|
309
317
|
this.emitColorChange()
|
|
310
318
|
event.target.classList.remove("hakumi-color-picker-input-invalid")
|
|
@@ -343,7 +351,7 @@ export default class extends RegistryController {
|
|
|
343
351
|
if (!this.hasSaturationTarget) return
|
|
344
352
|
|
|
345
353
|
const hue = this.hsv.h
|
|
346
|
-
const baseColor =
|
|
354
|
+
const baseColor = hsvToRgb(hue, 100, 100)
|
|
347
355
|
this.saturationTarget.style.backgroundColor = `rgb(${baseColor.r}, ${baseColor.g}, ${baseColor.b})`
|
|
348
356
|
}
|
|
349
357
|
|
|
@@ -371,7 +379,7 @@ export default class extends RegistryController {
|
|
|
371
379
|
updateAlphaSlider() {
|
|
372
380
|
if (!this.hasAlphaSliderTarget) return
|
|
373
381
|
|
|
374
|
-
const rgb =
|
|
382
|
+
const rgb = hsvToRgb(this.hsv.h, this.hsv.s, this.hsv.v)
|
|
375
383
|
const colorStr = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`
|
|
376
384
|
|
|
377
385
|
this.alphaSliderTarget.style.background = `
|
|
@@ -424,282 +432,12 @@ export default class extends RegistryController {
|
|
|
424
432
|
this.hiddenInputTarget.dispatchEvent(new Event("change", { bubbles: true }))
|
|
425
433
|
}
|
|
426
434
|
|
|
427
|
-
// ===== COLOR
|
|
435
|
+
// ===== COLOR FORMATTING =====
|
|
428
436
|
|
|
429
437
|
getCurrentColor() {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
case "rgb":
|
|
434
|
-
return this.hsvToRgbString(this.hsv.h, this.hsv.s, this.hsv.v, this.alpha)
|
|
435
|
-
case "hsl":
|
|
436
|
-
return this.hsvToHslString(this.hsv.h, this.hsv.s, this.hsv.v, this.alpha)
|
|
437
|
-
case "hsb":
|
|
438
|
-
return this.hsvToHsbString(this.hsv.h, this.hsv.s, this.hsv.v, this.alpha)
|
|
439
|
-
default:
|
|
440
|
-
return this.hsvToHex(this.hsv.h, this.hsv.s, this.hsv.v, this.alpha)
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
parseColorToHSV(color) {
|
|
445
|
-
if (!color) return { h: 215, s: 91, v: 100 }
|
|
446
|
-
|
|
447
|
-
color = color.trim()
|
|
448
|
-
|
|
449
|
-
// HEX
|
|
450
|
-
if (color.startsWith("#")) {
|
|
451
|
-
return this.hexToHsv(color)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// RGB/RGBA
|
|
455
|
-
if (color.startsWith("rgb")) {
|
|
456
|
-
return this.rgbStringToHsv(color)
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// HSL/HSLA
|
|
460
|
-
if (color.startsWith("hsl")) {
|
|
461
|
-
return this.hslStringToHsv(color)
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// HSB/HSBA (treat as HSV)
|
|
465
|
-
if (color.startsWith("hsb")) {
|
|
466
|
-
return this.hsbStringToHsv(color)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return { h: 215, s: 91, v: 100 }
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
extractAlpha(color) {
|
|
473
|
-
if (!color) return 1
|
|
474
|
-
|
|
475
|
-
color = color.trim()
|
|
476
|
-
|
|
477
|
-
// RGBA
|
|
478
|
-
if (color.startsWith("rgba")) {
|
|
479
|
-
const match = color.match(/rgba?\(([^)]+)\)/)
|
|
480
|
-
if (match) {
|
|
481
|
-
const parts = match[1].split(",").map(p => p.trim())
|
|
482
|
-
if (parts[3]) return parseFloat(parts[3])
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// HSLA
|
|
487
|
-
if (color.startsWith("hsla")) {
|
|
488
|
-
const match = color.match(/hsla?\(([^)]+)\)/)
|
|
489
|
-
if (match) {
|
|
490
|
-
const parts = match[1].split(",").map(p => p.trim())
|
|
491
|
-
if (parts[3]) return parseFloat(parts[3])
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
// HEX with alpha (#RRGGBBAA)
|
|
496
|
-
if (color.startsWith("#") && color.length === 9) {
|
|
497
|
-
const alpha = parseInt(color.slice(7, 9), 16)
|
|
498
|
-
return Math.round((alpha / 255) * 100) / 100
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return 1
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// HSV to RGB
|
|
505
|
-
hsvToRgb(h, s, v) {
|
|
506
|
-
h = h / 360
|
|
507
|
-
s = s / 100
|
|
508
|
-
v = v / 100
|
|
509
|
-
|
|
510
|
-
const i = Math.floor(h * 6)
|
|
511
|
-
const f = h * 6 - i
|
|
512
|
-
const p = v * (1 - s)
|
|
513
|
-
const q = v * (1 - f * s)
|
|
514
|
-
const t = v * (1 - (1 - f) * s)
|
|
515
|
-
|
|
516
|
-
let r, g, b
|
|
517
|
-
|
|
518
|
-
switch (i % 6) {
|
|
519
|
-
case 0: r = v; g = t; b = p; break
|
|
520
|
-
case 1: r = q; g = v; b = p; break
|
|
521
|
-
case 2: r = p; g = v; b = t; break
|
|
522
|
-
case 3: r = p; g = q; b = v; break
|
|
523
|
-
case 4: r = t; g = p; b = v; break
|
|
524
|
-
case 5: r = v; g = p; b = q; break
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
return {
|
|
528
|
-
r: Math.round(r * 255),
|
|
529
|
-
g: Math.round(g * 255),
|
|
530
|
-
b: Math.round(b * 255)
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
// RGB to HSV
|
|
535
|
-
rgbToHsv(r, g, b) {
|
|
536
|
-
r = r / 255
|
|
537
|
-
g = g / 255
|
|
538
|
-
b = b / 255
|
|
539
|
-
|
|
540
|
-
const max = Math.max(r, g, b)
|
|
541
|
-
const min = Math.min(r, g, b)
|
|
542
|
-
const delta = max - min
|
|
543
|
-
|
|
544
|
-
let h = 0
|
|
545
|
-
let s = max === 0 ? 0 : delta / max
|
|
546
|
-
let v = max
|
|
547
|
-
|
|
548
|
-
if (delta !== 0) {
|
|
549
|
-
if (max === r) {
|
|
550
|
-
h = ((g - b) / delta + (g < b ? 6 : 0)) / 6
|
|
551
|
-
} else if (max === g) {
|
|
552
|
-
h = ((b - r) / delta + 2) / 6
|
|
553
|
-
} else {
|
|
554
|
-
h = ((r - g) / delta + 4) / 6
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return {
|
|
559
|
-
h: Math.round(h * 360),
|
|
560
|
-
s: Math.round(s * 100),
|
|
561
|
-
v: Math.round(v * 100)
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
// HEX conversions
|
|
566
|
-
hexToHsv(hex) {
|
|
567
|
-
hex = hex.replace("#", "")
|
|
568
|
-
|
|
569
|
-
const r = parseInt(hex.slice(0, 2), 16)
|
|
570
|
-
const g = parseInt(hex.slice(2, 4), 16)
|
|
571
|
-
const b = parseInt(hex.slice(4, 6), 16)
|
|
572
|
-
|
|
573
|
-
return this.rgbToHsv(r, g, b)
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
hsvToHex(h, s, v, alpha = 1) {
|
|
577
|
-
const rgb = this.hsvToRgb(h, s, v)
|
|
578
|
-
const hex = `#${this.toHex(rgb.r)}${this.toHex(rgb.g)}${this.toHex(rgb.b)}`
|
|
579
|
-
|
|
580
|
-
if (alpha < 1 && !this.disabledAlphaValue) {
|
|
581
|
-
const alphaHex = this.toHex(Math.round(alpha * 255))
|
|
582
|
-
return `${hex}${alphaHex}`
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return hex
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
toHex(n) {
|
|
589
|
-
const hex = n.toString(16)
|
|
590
|
-
return hex.length === 1 ? "0" + hex : hex
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// RGB string conversions
|
|
594
|
-
rgbStringToHsv(rgbString) {
|
|
595
|
-
const match = rgbString.match(/rgba?\(([^)]+)\)/)
|
|
596
|
-
if (!match) return { h: 215, s: 91, v: 100 }
|
|
597
|
-
|
|
598
|
-
const [r, g, b] = match[1].split(",").map(p => parseInt(p.trim()))
|
|
599
|
-
return this.rgbToHsv(r, g, b)
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
hsvToRgbString(h, s, v, alpha = 1) {
|
|
603
|
-
const rgb = this.hsvToRgb(h, s, v)
|
|
604
|
-
|
|
605
|
-
if (alpha < 1 && !this.disabledAlphaValue) {
|
|
606
|
-
return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// HSL conversions
|
|
613
|
-
hslStringToHsv(hslString) {
|
|
614
|
-
const match = hslString.match(/hsla?\(([^)]+)\)/)
|
|
615
|
-
if (!match) return { h: 215, s: 91, v: 100 }
|
|
616
|
-
|
|
617
|
-
const parts = match[1].split(",").map(p => p.trim())
|
|
618
|
-
const h = parseFloat(parts[0])
|
|
619
|
-
const s = parseFloat(parts[1])
|
|
620
|
-
const l = parseFloat(parts[2])
|
|
621
|
-
|
|
622
|
-
return this.hslToHsv(h, s, l)
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
hslToHsv(h, s, l) {
|
|
626
|
-
s = s / 100
|
|
627
|
-
l = l / 100
|
|
628
|
-
|
|
629
|
-
const v = l + s * Math.min(l, 1 - l)
|
|
630
|
-
const sv = v === 0 ? 0 : 2 * (1 - l / v)
|
|
631
|
-
|
|
632
|
-
return {
|
|
633
|
-
h: Math.round(h),
|
|
634
|
-
s: Math.round(sv * 100),
|
|
635
|
-
v: Math.round(v * 100)
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
hsvToHsl(h, s, v) {
|
|
640
|
-
s = s / 100
|
|
641
|
-
v = v / 100
|
|
642
|
-
|
|
643
|
-
const l = v * (1 - s / 2)
|
|
644
|
-
const sl = l === 0 || l === 1 ? 0 : (v - l) / Math.min(l, 1 - l)
|
|
645
|
-
|
|
646
|
-
return {
|
|
647
|
-
h: Math.round(h),
|
|
648
|
-
s: Math.round(sl * 100),
|
|
649
|
-
l: Math.round(l * 100)
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
hsvToHslString(h, s, v, alpha = 1) {
|
|
654
|
-
const hsl = this.hsvToHsl(h, s, v)
|
|
655
|
-
|
|
656
|
-
if (alpha < 1 && !this.disabledAlphaValue) {
|
|
657
|
-
return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha})`
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
// HSB conversions (HSB is same as HSV)
|
|
664
|
-
hsbStringToHsv(hsbString) {
|
|
665
|
-
const match = hsbString.match(/hsba?\(([^)]+)\)/)
|
|
666
|
-
if (!match) return { h: 215, s: 91, v: 100 }
|
|
667
|
-
|
|
668
|
-
const parts = match[1].split(",").map(p => p.trim())
|
|
669
|
-
return {
|
|
670
|
-
h: Math.round(parseFloat(parts[0])),
|
|
671
|
-
s: Math.round(parseFloat(parts[1])),
|
|
672
|
-
v: Math.round(parseFloat(parts[2]))
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
hsvToHsbString(h, s, v, alpha = 1) {
|
|
677
|
-
if (alpha < 1 && !this.disabledAlphaValue) {
|
|
678
|
-
return `hsba(${h}, ${s}%, ${v}%, ${alpha})`
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
return `hsb(${h}, ${s}%, ${v}%)`
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// Color validation
|
|
685
|
-
isValidColor(color) {
|
|
686
|
-
if (!color) return false
|
|
687
|
-
|
|
688
|
-
color = color.trim()
|
|
689
|
-
|
|
690
|
-
// HEX
|
|
691
|
-
if (/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(color)) return true
|
|
692
|
-
|
|
693
|
-
// RGB/RGBA
|
|
694
|
-
if (/^rgba?\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*(,\s*[\d.]+\s*)?\)$/.test(color)) return true
|
|
695
|
-
|
|
696
|
-
// HSL/HSLA
|
|
697
|
-
if (/^hsla?\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*(,\s*[\d.]+\s*)?\)$/.test(color)) return true
|
|
698
|
-
|
|
699
|
-
// HSB/HSBA
|
|
700
|
-
if (/^hsba?\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*(,\s*[\d.]+\s*)?\)$/.test(color)) return true
|
|
701
|
-
|
|
702
|
-
return false
|
|
438
|
+
return formatHsvColor(this.hsv, this.alpha, this.formatValue, {
|
|
439
|
+
disabledAlpha: this.disabledAlphaValue
|
|
440
|
+
})
|
|
703
441
|
}
|
|
704
442
|
|
|
705
443
|
// ===== UTILS =====
|