@hakumi-dev/hakumi-components 0.1.17-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.
Files changed (56) hide show
  1. package/README.md +218 -369
  2. package/app/javascript/hakumi_components/controllers/hakumi/admin_panel_controller.js +5 -7
  3. package/app/javascript/hakumi_components/controllers/hakumi/back_top_controller.js +1 -1
  4. package/app/javascript/hakumi_components/controllers/hakumi/button_controller.js +108 -2
  5. package/app/javascript/hakumi_components/controllers/hakumi/calendar_controller.js +183 -95
  6. package/app/javascript/hakumi_components/controllers/hakumi/color_picker_controller.js +23 -285
  7. package/app/javascript/hakumi_components/controllers/hakumi/date_picker_controller.js +274 -262
  8. package/app/javascript/hakumi_components/controllers/hakumi/float_button_group_controller.js +2 -2
  9. package/app/javascript/hakumi_components/controllers/hakumi/message_controller.js +4 -2
  10. package/app/javascript/hakumi_components/controllers/hakumi/modal_controller.js +119 -125
  11. package/app/javascript/hakumi_components/controllers/hakumi/table/editable.js +291 -0
  12. package/app/javascript/hakumi_components/controllers/hakumi/table_controller.js +166 -366
  13. package/app/javascript/hakumi_components/controllers/hakumi/tabs_controller.js +8 -2
  14. package/app/javascript/hakumi_components/controllers/hakumi/tag_controller.js +27 -25
  15. package/app/javascript/hakumi_components/controllers/hakumi/tag_group_controller.js +19 -18
  16. package/app/javascript/hakumi_components/controllers/hakumi/theme_controller.js +116 -117
  17. package/app/javascript/hakumi_components/controllers/hakumi/transfer_controller.js +17 -1
  18. package/app/javascript/hakumi_components/controllers/hakumi/tree_controller.js +363 -78
  19. package/app/javascript/hakumi_components/controllers/hakumi/typography_controller.js +3 -3
  20. package/app/javascript/hakumi_components/controllers/hakumi/upload_controller.js +320 -204
  21. package/app/javascript/hakumi_components/core/render_component.js +37 -11
  22. package/app/javascript/hakumi_components/utils/color_helper.js +262 -0
  23. package/app/javascript/stylesheets/_base.scss +9 -0
  24. package/app/javascript/stylesheets/_hakumi_components.scss +1 -0
  25. package/app/javascript/stylesheets/components/_breadcrumb.scss +2 -2
  26. package/app/javascript/stylesheets/components/_calendar.scss +13 -13
  27. package/app/javascript/stylesheets/components/_cascader.scss +5 -5
  28. package/app/javascript/stylesheets/components/_checkbox.scss +9 -11
  29. package/app/javascript/stylesheets/components/_color_picker.scss +11 -11
  30. package/app/javascript/stylesheets/components/_date_picker.scss +4 -4
  31. package/app/javascript/stylesheets/components/_descriptions.scss +2 -2
  32. package/app/javascript/stylesheets/components/_drawer.scss +3 -3
  33. package/app/javascript/stylesheets/components/_dropdown.scss +2 -2
  34. package/app/javascript/stylesheets/components/_flex.scss +1 -1
  35. package/app/javascript/stylesheets/components/_float_button.scss +5 -5
  36. package/app/javascript/stylesheets/components/_form_item.scss +92 -0
  37. package/app/javascript/stylesheets/components/_image.scss +15 -15
  38. package/app/javascript/stylesheets/components/_input.scss +23 -113
  39. package/app/javascript/stylesheets/components/_layout.scss +27 -26
  40. package/app/javascript/stylesheets/components/_menu.scss +15 -15
  41. package/app/javascript/stylesheets/components/_modal.scss +13 -13
  42. package/app/javascript/stylesheets/components/_notification.scss +3 -3
  43. package/app/javascript/stylesheets/components/_popover.scss +1 -1
  44. package/app/javascript/stylesheets/components/_segmented.scss +3 -3
  45. package/app/javascript/stylesheets/components/_select.scss +6 -6
  46. package/app/javascript/stylesheets/components/_slider.scss +1 -1
  47. package/app/javascript/stylesheets/components/_spin.scss +2 -2
  48. package/app/javascript/stylesheets/components/_steps.scss +10 -10
  49. package/app/javascript/stylesheets/components/_switch.scss +11 -10
  50. package/app/javascript/stylesheets/components/_table.scss +6 -6
  51. package/app/javascript/stylesheets/components/_tag.scss +2 -2
  52. package/app/javascript/stylesheets/components/_tooltip.scss +4 -4
  53. package/app/javascript/stylesheets/components/_tree_select.scss +3 -3
  54. package/app/javascript/stylesheets/components/_typography.scss +3 -3
  55. package/app/javascript/stylesheets/components/_upload.scss +4 -4
  56. 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 = this.parseColorToHSV(initialColor)
42
- this.alpha = this.extractAlpha(initialColor)
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 = { h: 215, s: 91, v: 100 }
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 = this.parseColorToHSV(value)
156
- this.alpha = this.extractAlpha(value)
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 (this.isValidColor(value)) {
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 (this.isValidColor(value)) {
306
- this.hsv = this.parseColorToHSV(value)
307
- this.alpha = this.extractAlpha(value)
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 = this.hsvToRgb(hue, 100, 100)
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 = this.hsvToRgb(this.hsv.h, this.hsv.s, this.hsv.v)
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 CONVERSION =====
435
+ // ===== COLOR FORMATTING =====
428
436
 
429
437
  getCurrentColor() {
430
- switch (this.formatValue) {
431
- case "hex":
432
- return this.hsvToHex(this.hsv.h, this.hsv.s, this.hsv.v, this.alpha)
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 =====