hakumi_components 0.1.16.pre → 0.1.17.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 (134) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +169 -23
  3. data/app/assets/javascripts/hakumi_components.js +12 -12
  4. data/app/assets/stylesheets/hakumi_components.css +1 -1
  5. data/app/components/hakumi/alert/component.html.erb +12 -8
  6. data/app/components/hakumi/alert/component.rb +18 -62
  7. data/app/components/hakumi/base_component.rb +13 -0
  8. data/app/components/hakumi/card/component.html.erb +14 -22
  9. data/app/components/hakumi/card/component.rb +38 -31
  10. data/app/components/hakumi/checkbox/component.html.erb +39 -21
  11. data/app/components/hakumi/checkbox/component.rb +12 -2
  12. data/app/components/hakumi/collapse/component.html.erb +2 -2
  13. data/app/components/hakumi/collapse/component.rb +1 -1
  14. data/app/components/hakumi/collapse/panel/component.rb +9 -0
  15. data/app/components/hakumi/color_picker/component.rb +0 -4
  16. data/app/components/hakumi/drawer/component.html.erb +7 -7
  17. data/app/components/hakumi/drawer/component.rb +12 -19
  18. data/app/components/hakumi/input/component.rb +0 -2
  19. data/app/components/hakumi/input/text_area/component.rb +0 -2
  20. data/app/components/hakumi/input_number/component.rb +3 -4
  21. data/app/components/hakumi/mentions/component.rb +0 -1
  22. data/app/components/hakumi/modal/component.html.erb +40 -0
  23. data/app/components/hakumi/modal/component.rb +24 -102
  24. data/app/components/hakumi/modal/confirm/component.html.erb +23 -0
  25. data/app/components/hakumi/modal/confirm/component.rb +23 -41
  26. data/app/components/hakumi/modal/error/component.rb +12 -11
  27. data/app/components/hakumi/modal/info/component.rb +12 -11
  28. data/app/components/hakumi/modal/success/component.rb +12 -11
  29. data/app/components/hakumi/modal/warning/component.rb +15 -10
  30. data/app/components/hakumi/popconfirm/component.html.erb +25 -25
  31. data/app/components/hakumi/popconfirm/component.rb +11 -27
  32. data/app/components/hakumi/rate/component.rb +0 -1
  33. data/app/components/hakumi/segmented/component.rb +0 -4
  34. data/app/components/hakumi/slider/component.rb +2 -6
  35. data/app/components/hakumi/statistic/component.rb +0 -4
  36. data/app/components/hakumi/switch/component.html.erb +4 -0
  37. data/app/components/hakumi/switch/component.rb +1 -2
  38. data/app/components/hakumi/table/component.rb +3 -229
  39. data/app/components/hakumi/table/concerns/columns.rb +1 -1
  40. data/app/components/hakumi/table/concerns/editable.rb +121 -0
  41. data/app/components/hakumi/table/concerns/ellipsis.rb +63 -0
  42. data/app/components/hakumi/table/concerns/fixed_columns.rb +87 -0
  43. data/app/components/hakumi/transfer/component.rb +0 -4
  44. data/app/controllers/{hakumi_components → hakumi}/components_controller.rb +2 -2
  45. data/app/form_builders/hakumi/form_builder.rb +217 -175
  46. data/app/helpers/hakumi/form_helper.rb +39 -0
  47. data/app/javascript/hakumi_components/controllers/base/registry_controller.js +83 -3
  48. data/app/javascript/hakumi_components/controllers/hakumi/affix_controller.js +0 -23
  49. data/app/javascript/hakumi_components/controllers/hakumi/alert_controller.js +2 -1
  50. data/app/javascript/hakumi_components/controllers/hakumi/button_controller.js +0 -7
  51. data/app/javascript/hakumi_components/controllers/hakumi/calendar_controller.js +0 -2
  52. data/app/javascript/hakumi_components/controllers/hakumi/color_picker_controller.js +1 -6
  53. data/app/javascript/hakumi_components/controllers/hakumi/date_picker_controller.js +28 -34
  54. data/app/javascript/hakumi_components/controllers/hakumi/drawer_controller.js +2 -1
  55. data/app/javascript/hakumi_components/controllers/hakumi/form_item_controller.js +9 -63
  56. data/app/javascript/hakumi_components/controllers/hakumi/mentions_controller.js +4 -11
  57. data/app/javascript/hakumi_components/controllers/hakumi/message_controller.js +1 -1
  58. data/app/javascript/hakumi_components/controllers/hakumi/modal_controller.js +4 -20
  59. data/app/javascript/hakumi_components/controllers/hakumi/notification_controller.js +1 -1
  60. data/app/javascript/hakumi_components/controllers/hakumi/popconfirm_controller.js +33 -27
  61. data/app/javascript/hakumi_components/controllers/hakumi/popover_controller.js +2 -23
  62. data/app/javascript/hakumi_components/controllers/hakumi/qr_code_controller.js +0 -20
  63. data/app/javascript/hakumi_components/controllers/hakumi/segmented_controller.js +0 -2
  64. data/app/javascript/hakumi_components/controllers/hakumi/spin_controller.js +1 -19
  65. data/app/javascript/hakumi_components/controllers/hakumi/statistic_controller.js +0 -2
  66. data/app/javascript/hakumi_components/controllers/hakumi/table_controller.js +48 -74
  67. data/app/javascript/hakumi_components/controllers/hakumi/tag_controller.js +15 -14
  68. data/app/javascript/hakumi_components/controllers/hakumi/tag_group_controller.js +14 -13
  69. data/app/javascript/hakumi_components/controllers/hakumi/theme_controller.js +24 -1
  70. data/app/javascript/hakumi_components/controllers/hakumi/time_picker_controller.js +3 -7
  71. data/app/javascript/hakumi_components/controllers/hakumi/timeline_controller.js +0 -16
  72. data/app/javascript/hakumi_components/controllers/hakumi/transfer_controller.js +2 -2
  73. data/app/javascript/hakumi_components/controllers/hakumi/tree_controller.js +0 -2
  74. data/app/javascript/hakumi_components/controllers/hakumi/tree_select_controller.js +3 -3
  75. data/app/javascript/hakumi_components/controllers/hakumi/upload_controller.js +12 -26
  76. data/app/javascript/hakumi_components/core/persistence.js +3 -3
  77. data/app/javascript/hakumi_components/core/render_component.js +3 -1
  78. data/app/javascript/lib/validation_manager.js +101 -0
  79. data/app/javascript/stylesheets/_theme-tokens.scss +2 -1
  80. data/app/javascript/stylesheets/components/_modal.scss +13 -0
  81. data/app/services/{hakumi_components → hakumi}/component_handler.rb +1 -1
  82. data/app/services/hakumi/icon/loader.rb +2 -2
  83. data/app/services/hakumi/illustrations/loader.rb +3 -3
  84. data/app/views/hakumi/_drawer.html.erb +21 -0
  85. data/app/views/hakumi/_modal.html.erb +18 -0
  86. data/lib/hakumi_components/documentation.rb +127 -0
  87. data/lib/hakumi_components/engine.rb +13 -4
  88. data/lib/hakumi_components/rails/attribute_introspection.rb +1 -1
  89. data/lib/hakumi_components/rails/validation_introspection.rb +5 -5
  90. data/lib/hakumi_components/rails/validation_mapper.rb +484 -0
  91. data/lib/hakumi_components/rails.rb +2 -1
  92. data/lib/hakumi_components/version.rb +2 -2
  93. data/lib/hakumi_components.rb +3 -1
  94. data/lib/tasks/coverage.rake +37 -0
  95. data/sig/hakumi/base_component.rbs +5 -0
  96. data/sig/hakumi/checkbox/component.rbs +10 -0
  97. data/sig/hakumi/color_picker/component.rbs +0 -1
  98. data/sig/hakumi/form_builder.rbs +9 -1
  99. data/sig/{hakumi_components → hakumi}/rails/attribute_introspection.rbs +1 -1
  100. data/sig/{hakumi_components → hakumi}/rails/validation_introspection.rbs +1 -1
  101. data/sig/hakumi/rails/validation_mapper.rbs +53 -0
  102. data/sig/{hakumi_components → hakumi}/rails.rbs +1 -1
  103. data/sig/hakumi/segmented/component.rbs +0 -1
  104. data/sig/hakumi/slider/component.rbs +0 -1
  105. data/sig/hakumi/statistic/component.rbs +0 -2
  106. data/sig/hakumi/table/component.rbs +3 -4
  107. data/sig/hakumi/table/concerns/columns.rbs +2 -1
  108. data/sig/hakumi/table/concerns/editable.rbs +40 -0
  109. data/sig/hakumi/table/concerns/ellipsis.rbs +27 -0
  110. data/sig/hakumi/table/concerns/fixed_columns.rbs +33 -0
  111. data/sig/hakumi/transfer/component.rbs +0 -1
  112. data/sig/{hakumi_components.rbs → hakumi.rbs} +20 -3
  113. data/sig/rails/active_model/validations/comparison_validator.rbs +6 -0
  114. metadata +44 -29
  115. data/app/views/hakumi_components/_drawer.html.erb +0 -3
  116. data/app/views/hakumi_components/_modal.html.erb +0 -3
  117. /data/app/views/{hakumi_components → hakumi}/_admin_panel.html.erb +0 -0
  118. /data/app/views/{hakumi_components → hakumi}/_affix.html.erb +0 -0
  119. /data/app/views/{hakumi_components → hakumi}/_alert.html.erb +0 -0
  120. /data/app/views/{hakumi_components → hakumi}/_confirm.html.erb +0 -0
  121. /data/app/views/{hakumi_components → hakumi}/_message.html.erb +0 -0
  122. /data/app/views/{hakumi_components → hakumi}/_notification.html.erb +0 -0
  123. /data/app/views/{hakumi_components → hakumi}/_popconfirm.html.erb +0 -0
  124. /data/app/views/{hakumi_components → hakumi}/_popover.html.erb +0 -0
  125. /data/app/views/{hakumi_components → hakumi}/_qr_code.html.erb +0 -0
  126. /data/app/views/{hakumi_components → hakumi}/_result.html.erb +0 -0
  127. /data/app/views/{hakumi_components → hakumi}/_segmented.html.erb +0 -0
  128. /data/app/views/{hakumi_components → hakumi}/_skeleton.html.erb +0 -0
  129. /data/app/views/{hakumi_components → hakumi}/_spin.html.erb +0 -0
  130. /data/app/views/{hakumi_components → hakumi}/_statistic.html.erb +0 -0
  131. /data/app/views/{hakumi_components → hakumi}/_table.html.erb +0 -0
  132. /data/app/views/{hakumi_components → hakumi}/_tag.html.erb +0 -0
  133. /data/app/views/{hakumi_components → hakumi}/_timeline.html.erb +0 -0
  134. /data/app/views/{hakumi_components → hakumi}/_tree.html.erb +0 -0
@@ -2,6 +2,7 @@ import RegistryController from "../base/registry_controller.js"
2
2
  import { ensureOverlayContainer } from "../../core/overlay_container.js"
3
3
 
4
4
  export default class extends RegistryController {
5
+ static declarativeActions = ["close", "confirm", "cancel"]
5
6
  static targets = ["mask", "wrapper"]
6
7
  static values = {
7
8
  open: Boolean,
@@ -12,8 +13,6 @@ export default class extends RegistryController {
12
13
 
13
14
 
14
15
  setup() {
15
-
16
-
17
16
  const overlayContainer = ensureOverlayContainer()
18
17
  if (overlayContainer && this.element.parentElement !== overlayContainer) {
19
18
  overlayContainer.appendChild(this.element)
@@ -22,13 +21,10 @@ export default class extends RegistryController {
22
21
  if (!this.openValue) this.element.style.display = "none"
23
22
 
24
23
  this.handleOpenChange()
25
- this.boundHandleClick = this.handleClick.bind(this)
26
- this.element.addEventListener("click", this.boundHandleClick)
27
24
  }
28
25
 
29
26
  teardown() {
30
27
  if (this.animationTimeout) clearTimeout(this.animationTimeout)
31
- this.element.removeEventListener("click", this.boundHandleClick)
32
28
  }
33
29
 
34
30
  registerApi() {
@@ -66,19 +62,6 @@ export default class extends RegistryController {
66
62
  }
67
63
  }
68
64
 
69
- handleClick(event) {
70
- const closeTrigger = event.target.closest('[data-hakumi-modal-close]')
71
- const okTrigger = event.target.closest('[data-hakumi-modal-ok]')
72
-
73
- if (okTrigger) {
74
- this.handleOk(event)
75
- }
76
-
77
- if (closeTrigger) {
78
- this.close()
79
- }
80
- }
81
-
82
65
  openValueChanged() {
83
66
  this.handleOpenChange()
84
67
  }
@@ -127,7 +110,7 @@ export default class extends RegistryController {
127
110
  document.body.style.userSelect = ""
128
111
  document.body.style.webkitUserSelect = ""
129
112
 
130
- this.element.dispatchEvent(new CustomEvent("hakumi-component:hidden", { bubbles: true }))
113
+ this.dispatch("hidden")
131
114
  }
132
115
  this.animationTimeout = null
133
116
  }, 300)
@@ -157,7 +140,8 @@ export default class extends RegistryController {
157
140
  }
158
141
  }
159
142
 
160
- handleOk(_event) {
143
+ // Declarative action handlers (override base class)
144
+ handleConfirm(_event) {
161
145
  this.dispatch("ok")
162
146
  }
163
147
 
@@ -386,7 +386,7 @@ export default class extends RegistryController {
386
386
  }
387
387
 
388
388
  #dispatchHidden() {
389
- this.element.dispatchEvent(new CustomEvent("hakumi-component:hidden", { bubbles: true }))
389
+ this.dispatch("hidden")
390
390
  }
391
391
 
392
392
  #resolveIconMarkup(type, custom) {
@@ -1,6 +1,7 @@
1
1
  import RegistryController from "../base/registry_controller.js"
2
2
 
3
3
  export default class extends RegistryController {
4
+ static declarativeActions = ["confirm", "cancel"]
4
5
  static targets = ["trigger", "popover", "okButton", "cancelButton"]
5
6
  static values = {
6
7
  placement: { type: String, default: "top" },
@@ -29,9 +30,12 @@ export default class extends RegistryController {
29
30
  this.isOpen = this.openValue
30
31
  this.isLoading = false
31
32
  this.setupTriggerEvents()
32
- this.setupButtonEvents()
33
33
  this._popover = this.popoverTarget
34
34
 
35
+ // Listen for declarative actions on popover (may be moved to document.body)
36
+ this.boundPopoverAction = this.handleDeclarativeAction.bind(this)
37
+ this._popover.addEventListener("click", this.boundPopoverAction)
38
+
35
39
  if (this.isOpen) {
36
40
  this.show()
37
41
  }
@@ -39,13 +43,37 @@ export default class extends RegistryController {
39
43
 
40
44
  teardown() {
41
45
  this.removeTriggerEvents()
42
- this.removeButtonEvents()
46
+
47
+ if (this._popover) {
48
+ this._popover.removeEventListener("click", this.boundPopoverAction)
49
+ }
43
50
 
44
51
  if (this._popover && this._popover.parentElement === document.body) {
45
52
  this.element.appendChild(this._popover)
46
53
  }
47
54
  }
48
55
 
56
+ // Override to also check popover that may be moved to document.body
57
+ handleDeclarativeAction(event) {
58
+ const actionElement = event.target.closest("[data-hakumi-action]")
59
+ if (!actionElement) return
60
+
61
+ // Check if action element is inside this component OR inside our popover
62
+ const isInComponent = this.element.contains(actionElement)
63
+ const isInPopover = this._popover && this._popover.contains(actionElement)
64
+
65
+ if (!isInComponent && !isInPopover) return
66
+
67
+ const action = actionElement.dataset.hakumiAction
68
+ const actionMethod = this.getActionMethod(action)
69
+
70
+ if (typeof actionMethod === "function") {
71
+ event.preventDefault()
72
+ event.stopPropagation()
73
+ actionMethod.call(this, event, actionElement)
74
+ }
75
+ }
76
+
49
77
  setupTriggerEvents() {
50
78
  if (!this.hasTriggerTarget) return
51
79
 
@@ -95,27 +123,6 @@ export default class extends RegistryController {
95
123
  if (this.onDocumentClick) document.removeEventListener("click", this.onDocumentClick)
96
124
  }
97
125
 
98
- setupButtonEvents() {
99
- this.handleConfirm = this.confirm.bind(this)
100
- this.handleCancel = this.cancel.bind(this)
101
-
102
- if (this.hasOkButtonTarget) {
103
- this.okButtonTarget.addEventListener("click", this.handleConfirm)
104
- }
105
- if (this.hasCancelButtonTarget) {
106
- this.cancelButtonTarget.addEventListener("click", this.handleCancel)
107
- }
108
- }
109
-
110
- removeButtonEvents() {
111
- if (this.hasOkButtonTarget) {
112
- this.okButtonTarget.removeEventListener("click", this.handleConfirm)
113
- }
114
- if (this.hasCancelButtonTarget) {
115
- this.cancelButtonTarget.removeEventListener("click", this.handleCancel)
116
- }
117
- }
118
-
119
126
  toggle() {
120
127
  this.isOpen ? this.hide() : this.show()
121
128
  }
@@ -152,7 +159,7 @@ export default class extends RegistryController {
152
159
  }
153
160
  }, 300)
154
161
 
155
- this.dispatch("hidden", { prefix: "hakumi-popconfirm" })
162
+ this.dispatch("hidden")
156
163
  }
157
164
 
158
165
  open() { this.show() }
@@ -164,7 +171,6 @@ export default class extends RegistryController {
164
171
  const detail = { api: this.element.hakumiComponent.api, promise: null }
165
172
  const confirmEvent = this.dispatch("confirm", {
166
173
  cancelable: true,
167
- prefix: "hakumi-popconfirm",
168
174
  detail
169
175
  })
170
176
 
@@ -177,7 +183,7 @@ export default class extends RegistryController {
177
183
  this.hide()
178
184
  } catch (error) {
179
185
  console.error("[HakumiComponents] Popconfirm async error:", error)
180
- this.dispatch("confirm-error", { detail: { error }, prefix: "hakumi-popconfirm" })
186
+ this.dispatch("confirmError", { detail: { error } })
181
187
  } finally {
182
188
  this.setLoading(false)
183
189
  }
@@ -188,7 +194,7 @@ export default class extends RegistryController {
188
194
 
189
195
  cancel(e) {
190
196
  if (e) e.stopPropagation()
191
- this.dispatch("cancel", { prefix: "hakumi-popconfirm" })
197
+ this.dispatch("cancel")
192
198
  this.hide()
193
199
  }
194
200
 
@@ -34,8 +34,6 @@ export default class extends RegistryController {
34
34
  singleton: false,
35
35
  api
36
36
  }
37
-
38
- this.#exposeApi(api)
39
37
  }
40
38
 
41
39
  setup() {
@@ -60,11 +58,6 @@ export default class extends RegistryController {
60
58
  }
61
59
  }
62
60
 
63
- disconnect() {
64
- delete this.element.hakumiPopover
65
- super.disconnect()
66
- }
67
-
68
61
  setupTriggerEvents() {
69
62
  if (!this.hasTriggerTarget) return
70
63
 
@@ -163,8 +156,7 @@ export default class extends RegistryController {
163
156
 
164
157
  this.isOpen = false
165
158
  this.updateVisibility()
166
- this.dispatch("hidden", { prefix: "hakumi-popover" })
167
- this.element.dispatchEvent(new CustomEvent("hakumi-component:hidden", { bubbles: true }))
159
+ this.dispatch("hidden")
168
160
  }
169
161
 
170
162
  open() {
@@ -175,8 +167,7 @@ export default class extends RegistryController {
175
167
  close() {
176
168
  this.isOpen = false
177
169
  this.updateVisibility()
178
- this.dispatch("hidden", { prefix: "hakumi-popover" })
179
- this.element.dispatchEvent(new CustomEvent("hakumi-component:hidden", { bubbles: true }))
170
+ this.dispatch("hidden")
180
171
  }
181
172
 
182
173
  toggle() {
@@ -423,18 +414,6 @@ export default class extends RegistryController {
423
414
  return this.hasOpenValue && this.openValue !== undefined
424
415
  }
425
416
 
426
- #exposeApi(api) {
427
- this.element.hakumiPopover = {
428
- open: () => api.open(),
429
- close: () => api.close(),
430
- toggle: () => api.toggle(),
431
- isOpen: () => api.isOpen(),
432
- getState: () => api.getState(),
433
- setPlacement: (placement) => api.setPlacement(placement),
434
- setOpen: (value) => api.setOpen(value)
435
- }
436
- }
437
-
438
417
  #bindOutsideListeners() {
439
418
  if (this.boundOutsideHandlers || !this.triggerModes.includes("click")) return
440
419
 
@@ -44,8 +44,6 @@ export default class extends RegistryController {
44
44
  singleton: false,
45
45
  api
46
46
  }
47
-
48
- this.#exposeApi(api)
49
47
  }
50
48
 
51
49
  setup() {
@@ -56,7 +54,6 @@ export default class extends RegistryController {
56
54
 
57
55
  disconnect() {
58
56
  this.#unwatchThemeChanges()
59
- delete this.element.hakumiQrCode
60
57
  super.disconnect()
61
58
  }
62
59
 
@@ -278,23 +275,6 @@ export default class extends RegistryController {
278
275
  return computed || fallback
279
276
  }
280
277
 
281
- #exposeApi(api) {
282
- this.element.hakumiQrCode = {
283
- getValue: () => api.getValue(),
284
- setValue: (value) => api.setValue(value),
285
- getSize: () => api.getSize(),
286
- setSize: (size) => api.setSize(size),
287
- getType: () => api.getType(),
288
- setType: (type) => api.setType(type),
289
- setColors: (options) => api.setColors(options),
290
- setErrorLevel: (level) => api.setErrorLevel(level),
291
- getDataUrl: () => api.getDataUrl(),
292
- download: (filename) => api.download(filename),
293
- rerender: () => api.rerender(),
294
- getState: () => api.getState()
295
- }
296
- }
297
-
298
278
  #applySizeStyle() {
299
279
  if (!this.sizeValue) return
300
280
  const value = Math.max(1, Number(this.sizeValue))
@@ -44,7 +44,6 @@ export default class extends RegistryController {
44
44
 
45
45
  disconnect() {
46
46
  this._destroyResizeObserver()
47
- delete this.element.hakumiSegmented
48
47
  super.disconnect()
49
48
  }
50
49
 
@@ -84,7 +83,6 @@ export default class extends RegistryController {
84
83
  }
85
84
 
86
85
  #exposeApi(api) {
87
- this.element.hakumiSegmented = api
88
86
  }
89
87
 
90
88
  #updateSelection() {
@@ -28,13 +28,6 @@ export default class extends RegistryController {
28
28
  setTip: (value) => this.setTip(value)
29
29
  }
30
30
  }
31
-
32
- this.#exposeApi()
33
- }
34
-
35
- disconnect() {
36
- delete this.element.hakumiSpin
37
- super.disconnect()
38
31
  }
39
32
 
40
33
  spinningValueChanged() {
@@ -99,7 +92,7 @@ export default class extends RegistryController {
99
92
  this.element.setAttribute("aria-busy", this.spinningValue ? "true" : "false")
100
93
 
101
94
  if (this.visibleSpinning && !value && !silent) {
102
- this.element.dispatchEvent(new CustomEvent("hakumi-component:hidden", { bubbles: true }))
95
+ this.dispatch("hidden")
103
96
  }
104
97
 
105
98
  this.visibleSpinning = value
@@ -116,15 +109,4 @@ export default class extends RegistryController {
116
109
 
117
110
  this.progressElement.setAttribute("aria-valuenow", String(value))
118
111
  }
119
-
120
- #exposeApi() {
121
- this.element.hakumiSpin = {
122
- show: () => this.show(),
123
- hide: () => this.hide(),
124
- toggle: () => this.toggle(),
125
- isSpinning: () => this.spinningValue,
126
- setPercent: (value) => this.setPercent(value),
127
- setTip: (value) => this.setTip(value)
128
- }
129
- }
130
112
  }
@@ -60,7 +60,6 @@ export default class extends RegistryController {
60
60
 
61
61
  disconnect() {
62
62
  this.pause()
63
- delete this.element.hakumiStatistic
64
63
  super.disconnect()
65
64
  }
66
65
 
@@ -244,6 +243,5 @@ export default class extends RegistryController {
244
243
  }
245
244
 
246
245
  #exposeApi(api) {
247
- this.element.hakumiStatistic = api
248
246
  }
249
247
  }
@@ -109,7 +109,6 @@ export default class extends RegistryController {
109
109
  this._columnSortable = null
110
110
  }
111
111
 
112
- delete this.element.hakumiTable
113
112
  super.disconnect()
114
113
  }
115
114
 
@@ -229,7 +228,8 @@ export default class extends RegistryController {
229
228
  }
230
229
 
231
230
  setSelectedRowKeys(keys) {
232
- this._selectedRowKeys = new Set(Array(keys).map(String))
231
+ const keysArray = Array.isArray(keys) ? keys : [keys]
232
+ this._selectedRowKeys = new Set(keysArray.map(String))
233
233
  this.#syncSelection()
234
234
  this.#dispatchSelectionChange()
235
235
  }
@@ -298,7 +298,7 @@ export default class extends RegistryController {
298
298
  }
299
299
 
300
300
  setFilters(filters = {}) {
301
- this._filters = new Map(Object.entries(filters).map(([key, values]) => [key, Array(values)]))
301
+ this._filters = new Map(Object.entries(filters).map(([key, values]) => [key, Array.isArray(values) ? values : [values]]))
302
302
  this.#syncFilterInputs()
303
303
  this.#applyFiltersToRows()
304
304
  }
@@ -308,7 +308,8 @@ export default class extends RegistryController {
308
308
  }
309
309
 
310
310
  setExpandedRowKeys(keys) {
311
- this._expandedRowKeys = new Set(Array(keys).map(String))
311
+ const keysArray = Array.isArray(keys) ? keys : [keys]
312
+ this._expandedRowKeys = new Set(keysArray.map(String))
312
313
  this.#syncExpandedRows()
313
314
  }
314
315
 
@@ -676,35 +677,24 @@ export default class extends RegistryController {
676
677
  })
677
678
  })
678
679
 
679
- this.element.dispatchEvent(
680
- new CustomEvent("hakumi:table:row-editing", {
681
- bubbles: true,
682
- detail: { rowKey, save: saveRow, cancel: cancelRow }
683
- })
684
- )
680
+ this.dispatch("rowEditing", {
681
+ detail: { rowKey, save: saveRow, cancel: cancelRow }
682
+ })
685
683
  }
686
684
 
687
685
  #dispatchEdit(detail) {
688
- this.element.dispatchEvent(
689
- new CustomEvent("hakumi:table:edit", {
690
- bubbles: true,
691
- detail
692
- })
693
- )
686
+ this.dispatch("edit", { detail })
694
687
  }
695
688
 
696
689
  #dispatchRowEdit(detail) {
697
690
  const params = this.#changesToParams(detail.changes)
698
-
699
- this.element.dispatchEvent(
700
- new CustomEvent("hakumi:table:row-edit", {
701
- bubbles: true,
702
- detail: {
703
- ...detail,
704
- params
705
- }
706
- })
707
- )
691
+
692
+ this.dispatch("rowEdit", {
693
+ detail: {
694
+ ...detail,
695
+ params
696
+ }
697
+ })
708
698
  }
709
699
 
710
700
  #changesToParams(changes) {
@@ -735,15 +725,12 @@ export default class extends RegistryController {
735
725
  if (result === false) return false
736
726
 
737
727
  if (typeof result === "string") {
738
- this.element.dispatchEvent(
739
- new CustomEvent("hakumi:table:cell-update-prevented", {
740
- bubbles: true,
741
- detail: {
742
- ...detail,
743
- reason: result
744
- }
745
- })
746
- )
728
+ this.dispatch("cellUpdatePrevented", {
729
+ detail: {
730
+ ...detail,
731
+ reason: result
732
+ }
733
+ })
747
734
  return false
748
735
  }
749
736
 
@@ -773,7 +760,6 @@ export default class extends RegistryController {
773
760
  }
774
761
 
775
762
  #exposeApi(api) {
776
- this.element.hakumiTable = api
777
763
  }
778
764
 
779
765
  #isServerSide() {
@@ -1059,25 +1045,19 @@ export default class extends RegistryController {
1059
1045
  }
1060
1046
 
1061
1047
  #dispatchSelectionChange() {
1062
- this.element.dispatchEvent(
1063
- new CustomEvent("hakumi:table:selection-change", {
1064
- bubbles: true,
1065
- detail: { selectedRowKeys: this.getSelectedRowKeys() }
1066
- })
1067
- )
1048
+ this.dispatch("selectionChange", {
1049
+ detail: { selectedRowKeys: this.getSelectedRowKeys() }
1050
+ })
1068
1051
  }
1069
1052
 
1070
1053
  #dispatchChange() {
1071
- this.element.dispatchEvent(
1072
- new CustomEvent("hakumi:table:change", {
1073
- bubbles: true,
1074
- detail: {
1075
- selectedRowKeys: this.getSelectedRowKeys(),
1076
- sorter: this._sorter,
1077
- filters: this.getFilters()
1078
- }
1079
- })
1080
- )
1054
+ this.dispatch("change", {
1055
+ detail: {
1056
+ selectedRowKeys: this.getSelectedRowKeys(),
1057
+ sorter: this._sorter,
1058
+ filters: this.getFilters()
1059
+ }
1060
+ })
1081
1061
  }
1082
1062
 
1083
1063
  #parseJson(value, fallback) {
@@ -1168,31 +1148,25 @@ export default class extends RegistryController {
1168
1148
  }
1169
1149
 
1170
1150
  #dispatchRowReorder(oldIndex, newIndex, rowKey) {
1171
- this.element.dispatchEvent(
1172
- new CustomEvent("hakumi--table:rowReorder", {
1173
- bubbles: true,
1174
- detail: {
1175
- oldIndex,
1176
- newIndex,
1177
- rowKey,
1178
- order: this.getRowOrder()
1179
- }
1180
- })
1181
- )
1151
+ this.dispatch("rowReorder", {
1152
+ detail: {
1153
+ oldIndex,
1154
+ newIndex,
1155
+ rowKey,
1156
+ order: this.getRowOrder()
1157
+ }
1158
+ })
1182
1159
  }
1183
1160
 
1184
1161
  #dispatchColumnReorder(oldIndex, newIndex, columnKey) {
1185
- this.element.dispatchEvent(
1186
- new CustomEvent("hakumi--table:columnReorder", {
1187
- bubbles: true,
1188
- detail: {
1189
- oldIndex,
1190
- newIndex,
1191
- columnKey,
1192
- order: this.getColumnOrder()
1193
- }
1194
- })
1195
- )
1162
+ this.dispatch("columnReorder", {
1163
+ detail: {
1164
+ oldIndex,
1165
+ newIndex,
1166
+ columnKey,
1167
+ order: this.getColumnOrder()
1168
+ }
1169
+ })
1196
1170
  }
1197
1171
 
1198
1172
  }
@@ -7,16 +7,27 @@ export default class extends Controller {
7
7
  }
8
8
 
9
9
  connect() {
10
- this.#exposeApi()
11
-
10
+ this.element.hakumiComponent = {
11
+ name: "tag",
12
+ version: 1,
13
+ singleton: false,
14
+ api: {
15
+ close: () => this.close(),
16
+ toggle: () => this.toggle(),
17
+ check: () => this.check(),
18
+ uncheck: () => this.uncheck(),
19
+ isChecked: () => this.isChecked()
20
+ }
21
+ }
22
+
12
23
  if (this.checkableValue) {
13
24
  this.element.addEventListener("click", this.#handleClick)
14
25
  }
15
26
  }
16
27
 
17
28
  disconnect() {
18
- delete this.element.hakumiTag
19
-
29
+ delete this.element.hakumiComponent
30
+
20
31
  if (this.checkableValue) {
21
32
  this.element.removeEventListener("click", this.#handleClick)
22
33
  }
@@ -90,14 +101,4 @@ export default class extends Controller {
90
101
  #updateCheckedState() {
91
102
  this.element.classList.toggle("hakumi-tag-checkable-checked", this.checkedValue)
92
103
  }
93
-
94
- #exposeApi() {
95
- this.element.hakumiTag = {
96
- close: () => this.close(),
97
- toggle: () => this.toggle(),
98
- check: () => this.check(),
99
- uncheck: () => this.uncheck(),
100
- isChecked: () => this.isChecked()
101
- }
102
- }
103
104
  }
@@ -9,17 +9,28 @@ export default class extends Controller {
9
9
 
10
10
  connect() {
11
11
  this._sortable = null
12
-
12
+
13
13
  if (this.sortableValue) {
14
14
  this.#setupSortable()
15
15
  }
16
16
 
17
- this.#exposeApi()
17
+ this.element.hakumiComponent = {
18
+ name: "tag_group",
19
+ version: 1,
20
+ singleton: false,
21
+ api: {
22
+ enableSorting: () => this.enableSorting(),
23
+ disableSorting: () => this.disableSorting(),
24
+ isSortingEnabled: () => this.isSortingEnabled(),
25
+ getTags: () => this.getTags(),
26
+ getTagValues: () => this.getTagValues()
27
+ }
28
+ }
18
29
  }
19
30
 
20
31
  disconnect() {
21
32
  this.#destroySortable()
22
- delete this.element.hakumiTagGroup
33
+ delete this.element.hakumiComponent
23
34
  }
24
35
 
25
36
  sortableValueChanged() {
@@ -81,14 +92,4 @@ export default class extends Controller {
81
92
  this._sortable = null
82
93
  }
83
94
  }
84
-
85
- #exposeApi() {
86
- this.element.hakumiTagGroup = {
87
- enableSorting: () => this.enableSorting(),
88
- disableSorting: () => this.disableSorting(),
89
- isSortingEnabled: () => this.isSortingEnabled(),
90
- getTags: () => this.getTags(),
91
- getTagValues: () => this.getTagValues()
92
- }
93
- }
94
95
  }