@morscherlab/mld-sdk 0.7.2 → 0.7.3

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 (55) hide show
  1. package/dist/components/BaseInput.vue.d.ts +1 -0
  2. package/dist/components/BaseInput.vue.js +5 -2
  3. package/dist/components/BaseInput.vue.js.map +1 -1
  4. package/dist/components/BaseModal.vue.d.ts +6 -2
  5. package/dist/components/BaseModal.vue.js +54 -10
  6. package/dist/components/BaseModal.vue.js.map +1 -1
  7. package/dist/components/BaseSelect.vue.d.ts +1 -0
  8. package/dist/components/BaseSelect.vue.js +5 -2
  9. package/dist/components/BaseSelect.vue.js.map +1 -1
  10. package/dist/components/BaseTextarea.vue.d.ts +1 -0
  11. package/dist/components/BaseTextarea.vue.js +5 -2
  12. package/dist/components/BaseTextarea.vue.js.map +1 -1
  13. package/dist/components/ExperimentCodeBadge.vue.d.ts +8 -0
  14. package/dist/components/ExperimentCodeBadge.vue.js +19 -0
  15. package/dist/components/ExperimentCodeBadge.vue.js.map +1 -0
  16. package/dist/components/ExperimentCodeBadge.vue3.js +6 -0
  17. package/dist/components/ExperimentCodeBadge.vue3.js.map +1 -0
  18. package/dist/components/ExperimentDataViewer.vue.d.ts +29 -0
  19. package/dist/components/ExperimentDataViewer.vue.js +258 -0
  20. package/dist/components/ExperimentDataViewer.vue.js.map +1 -0
  21. package/dist/components/ExperimentDataViewer.vue3.js +6 -0
  22. package/dist/components/ExperimentDataViewer.vue3.js.map +1 -0
  23. package/dist/components/FormField.vue.d.ts +4 -1
  24. package/dist/components/FormField.vue.js +24 -12
  25. package/dist/components/FormField.vue.js.map +1 -1
  26. package/dist/components/index.d.ts +2 -0
  27. package/dist/components/index.js +14 -8
  28. package/dist/components/index.js.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +14 -8
  31. package/dist/index.js.map +1 -1
  32. package/dist/styles.css +298 -30
  33. package/dist/types/components.d.ts +23 -0
  34. package/dist/types/index.d.ts +1 -1
  35. package/package.json +1 -1
  36. package/src/components/BaseInput.vue +3 -0
  37. package/src/components/BaseModal.vue +59 -10
  38. package/src/components/BaseSelect.vue +3 -0
  39. package/src/components/BaseTextarea.vue +3 -0
  40. package/src/components/ExperimentCodeBadge.vue +20 -0
  41. package/src/components/ExperimentDataViewer.vue +250 -0
  42. package/src/components/FormField.vue +17 -4
  43. package/src/components/index.ts +4 -0
  44. package/src/index.ts +10 -0
  45. package/src/styles/components/button.css +4 -4
  46. package/src/styles/components/experiment-code-badge.css +13 -0
  47. package/src/styles/components/experiment-data-viewer.css +131 -0
  48. package/src/styles/components/modal.css +1 -1
  49. package/src/styles/components/select.css +1 -1
  50. package/src/styles/components/slider.css +4 -8
  51. package/src/styles/components/textarea.css +5 -1
  52. package/src/styles/index.css +2 -0
  53. package/src/styles/variables.css +7 -2
  54. package/src/types/components.ts +27 -0
  55. package/src/types/index.ts +4 -0
package/dist/styles.css CHANGED
@@ -59,14 +59,19 @@
59
59
 
60
60
  /* Semantic colors */
61
61
  --mld-success: #10B981;
62
+ --mld-success-hover: #059669;
62
63
  --mld-success-bg: rgba(16, 185, 129, 0.1);
63
64
  --mld-error: #EF4444;
65
+ --mld-error-hover: #DC2626;
64
66
  --mld-error-bg: rgba(239, 68, 68, 0.1);
65
67
  --mld-warning: #F59E0B;
66
68
  --mld-warning-bg: rgba(245, 158, 11, 0.1);
67
69
  --mld-info: #3B82F6;
68
70
  --mld-info-bg: rgba(59, 130, 246, 0.1);
69
71
 
72
+ /* Shared component tokens */
73
+ --mld-disabled-opacity: 0.6;
74
+
70
75
  /* Legacy aliases (for backwards compatibility) */
71
76
  --mld-bg-primary: var(--bg-primary);
72
77
  --mld-bg-secondary: var(--bg-secondary);
@@ -556,10 +561,10 @@ code, pre {
556
561
  background-color: var(--mld-success);
557
562
  }
558
563
  .hover\:bg-mld-success-hover:hover {
559
- background-color: #059669;
564
+ background-color: var(--mld-success-hover);
560
565
  }
561
566
  .hover\:bg-mld-danger-hover:hover {
562
- background-color: #DC2626;
567
+ background-color: var(--mld-error-hover);
563
568
  }
564
569
  .bg-mld-primary\/10 {
565
570
  background-color: rgba(99, 102, 241, 0.1);
@@ -1563,11 +1568,11 @@ html.dark .focus\:ring-offset-2:focus {
1563
1568
  border: none;
1564
1569
  box-sizing: border-box;
1565
1570
  }
1566
- .mld-button:focus {
1571
+ .mld-button:focus-visible {
1567
1572
  outline: none;
1568
1573
  box-shadow: 0 0 0 2px white, 0 0 0 4px var(--color-primary);
1569
1574
  }
1570
- html.dark .mld-button:focus {
1575
+ html.dark .mld-button:focus-visible {
1571
1576
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--color-primary);
1572
1577
  }
1573
1578
  .mld-button--disabled {
@@ -1605,14 +1610,14 @@ html.dark .mld-button:focus {
1605
1610
  color: white;
1606
1611
  }
1607
1612
  .mld-button--danger:hover:not(.mld-button--disabled) {
1608
- background-color: #DC2626;
1613
+ background-color: var(--mld-error-hover);
1609
1614
  }
1610
1615
  .mld-button--success {
1611
1616
  background-color: var(--mld-success);
1612
1617
  color: white;
1613
1618
  }
1614
1619
  .mld-button--success:hover:not(.mld-button--disabled) {
1615
- background-color: #059669;
1620
+ background-color: var(--mld-success-hover);
1616
1621
  }
1617
1622
  .mld-button--ghost {
1618
1623
  background-color: transparent;
@@ -3318,7 +3323,7 @@ html.dark .mld-checkbox__native:focus-visible + .mld-checkbox__box {
3318
3323
  padding: 0 !important;
3319
3324
  }
3320
3325
  .mld-modal__close {
3321
- padding: 0.25rem;
3326
+ padding: 0.5rem;
3322
3327
  border-radius: var(--mld-radius-sm);
3323
3328
  color: var(--text-muted);
3324
3329
  background: none;
@@ -4187,7 +4192,7 @@ html.dark .mld-radio-option__native:focus-visible + .mld-radio-option__circle {
4187
4192
  box-shadow: 0 0 0 2px var(--mld-error);
4188
4193
  }
4189
4194
  .mld-select__control--disabled {
4190
- opacity: 0.5;
4195
+ opacity: var(--mld-disabled-opacity);
4191
4196
  cursor: not-allowed;
4192
4197
  background-color: var(--bg-tertiary);
4193
4198
  }
@@ -4326,7 +4331,7 @@ html.dark .mld-radio-option__native:focus-visible + .mld-radio-option__circle {
4326
4331
  gap: 12px;
4327
4332
  }
4328
4333
  .mld-slider--disabled {
4329
- opacity: 0.5;
4334
+ opacity: var(--mld-disabled-opacity);
4330
4335
  cursor: not-allowed;
4331
4336
  }
4332
4337
  .mld-slider__container {
@@ -4341,16 +4346,13 @@ html.dark .mld-radio-option__native:focus-visible + .mld-radio-option__circle {
4341
4346
  left: 0;
4342
4347
  right: 0;
4343
4348
  border-radius: 9999px;
4344
- background-color: #E2E8F0;
4345
- }
4346
- html.dark .mld-slider__track {
4347
- background-color: #334155;
4349
+ background-color: var(--bg-tertiary);
4348
4350
  }
4349
4351
  .mld-slider__fill {
4350
4352
  position: absolute;
4351
4353
  left: 0;
4352
4354
  border-radius: 9999px;
4353
- background-color: #3B82F6;
4355
+ background-color: var(--color-primary);
4354
4356
  }
4355
4357
  .mld-slider__input {
4356
4358
  position: absolute;
@@ -4371,7 +4373,7 @@ html.dark .mld-slider__track {
4371
4373
  transform: translateX(-50%) translateY(-50%);
4372
4374
  border-radius: 9999px;
4373
4375
  background-color: white;
4374
- border: 2px solid #3B82F6;
4376
+ border: 2px solid var(--color-primary);
4375
4377
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
4376
4378
  pointer-events: none;
4377
4379
  transition: transform 150ms ease;
@@ -4589,6 +4591,9 @@ html.dark .mld-slider__track {
4589
4591
  .mld-textarea::placeholder {
4590
4592
  color: var(--text-muted);
4591
4593
  }
4594
+ .mld-textarea:hover:not(:focus):not(.mld-textarea--disabled):not(.mld-textarea--error) {
4595
+ border-color: var(--text-muted);
4596
+ }
4592
4597
  .mld-textarea:focus {
4593
4598
  outline: none;
4594
4599
  border-color: transparent;
@@ -4601,7 +4606,7 @@ html.dark .mld-slider__track {
4601
4606
  box-shadow: 0 0 0 2px var(--mld-error);
4602
4607
  }
4603
4608
  .mld-textarea--disabled {
4604
- opacity: 0.5;
4609
+ opacity: var(--mld-disabled-opacity);
4605
4610
  cursor: not-allowed;
4606
4611
  background-color: var(--bg-tertiary);
4607
4612
  }
@@ -12048,6 +12053,135 @@ html.dark .mld-settings-modal__option-btn--active {
12048
12053
  padding-top: 1rem;
12049
12054
  border-top: 1px solid var(--color-border, #e5e7eb);
12050
12055
  }
12056
+ .mld-data-viewer {
12057
+ border: 1px solid var(--mld-color-border, #e0e0e0);
12058
+ border-radius: var(--mld-radius-md, 8px);
12059
+ overflow: hidden;
12060
+ }
12061
+ .mld-data-viewer__header {
12062
+ display: flex;
12063
+ align-items: center;
12064
+ justify-content: space-between;
12065
+ padding: 8px 12px;
12066
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
12067
+ background: var(--mld-color-surface-1, #fafafa);
12068
+ gap: 8px;
12069
+ }
12070
+ .mld-data-viewer__controls { display: flex; gap: 8px; }
12071
+ .mld-data-viewer__actions { display: flex; gap: 4px; align-items: center; }
12072
+ .mld-data-viewer__content {
12073
+ padding: 12px;
12074
+ max-height: 600px;
12075
+ overflow-y: auto;
12076
+ }
12077
+ .mld-data-viewer__loading,
12078
+ .mld-data-viewer__empty {
12079
+ text-align: center;
12080
+ padding: 32px;
12081
+ color: var(--mld-color-text-muted, #999);
12082
+ }
12083
+ /* Summary view */
12084
+ .mld-summary {
12085
+ display: flex;
12086
+ flex-direction: column;
12087
+ gap: 16px;
12088
+ }
12089
+ /* Metadata pills row */
12090
+ .mld-summary__metadata {
12091
+ display: flex;
12092
+ flex-wrap: wrap;
12093
+ gap: 6px;
12094
+ }
12095
+ .mld-summary__pill {
12096
+ display: inline-flex;
12097
+ align-items: center;
12098
+ border-radius: 6px;
12099
+ overflow: hidden;
12100
+ font-size: 0.8125rem;
12101
+ line-height: 1;
12102
+ border: 1px solid var(--mld-color-border, #e0e0e0);
12103
+ }
12104
+ .mld-summary__pill--sm {
12105
+ font-size: 0.75rem;
12106
+ }
12107
+ .mld-summary__pill-key {
12108
+ padding: 4px 8px;
12109
+ background: var(--mld-color-surface-1, #f5f5f5);
12110
+ color: var(--mld-color-text-muted, #666);
12111
+ text-transform: capitalize;
12112
+ font-weight: 500;
12113
+ }
12114
+ .mld-summary__pill-value {
12115
+ padding: 4px 8px;
12116
+ color: var(--mld-color-text, #1a1a1a);
12117
+ }
12118
+ /* Section */
12119
+ .mld-summary__section {
12120
+ display: flex;
12121
+ flex-direction: column;
12122
+ gap: 12px;
12123
+ }
12124
+ .mld-summary__section-label {
12125
+ font-weight: 600;
12126
+ font-size: 0.875rem;
12127
+ color: var(--mld-color-text, #1a1a1a);
12128
+ }
12129
+ .mld-summary__section-count {
12130
+ font-size: 0.75rem;
12131
+ color: var(--mld-color-text-muted, #999);
12132
+ margin-left: 8px;
12133
+ }
12134
+ .mld-summary__table-header {
12135
+ display: flex;
12136
+ align-items: baseline;
12137
+ gap: 4px;
12138
+ }
12139
+ /* Group cards */
12140
+ .mld-summary__group-card {
12141
+ border: 1px solid var(--mld-color-border, #e0e0e0);
12142
+ border-radius: var(--mld-radius-md, 8px);
12143
+ overflow: hidden;
12144
+ }
12145
+ .mld-summary__group-header {
12146
+ display: flex;
12147
+ align-items: center;
12148
+ justify-content: space-between;
12149
+ padding: 10px 14px;
12150
+ background: var(--mld-color-surface-1, #fafafa);
12151
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
12152
+ }
12153
+ .mld-summary__group-label {
12154
+ font-weight: 600;
12155
+ font-size: 0.875rem;
12156
+ color: var(--mld-color-text, #1a1a1a);
12157
+ }
12158
+ .mld-summary__group-count {
12159
+ font-size: 0.75rem;
12160
+ color: var(--mld-color-text-muted, #999);
12161
+ background: var(--mld-color-surface-2, #eee);
12162
+ padding: 2px 8px;
12163
+ border-radius: 10px;
12164
+ }
12165
+ .mld-summary__group-meta {
12166
+ display: flex;
12167
+ flex-wrap: wrap;
12168
+ gap: 6px;
12169
+ padding: 8px 14px;
12170
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
12171
+ }
12172
+ .mld-exp-code {
12173
+ display: inline-flex;
12174
+ align-items: center;
12175
+ font-family: var(--mld-font-mono, ui-monospace, monospace);
12176
+ font-weight: 600;
12177
+ background: var(--mld-color-surface-2, #f0f0f0);
12178
+ color: var(--mld-color-text-secondary, #666);
12179
+ border-radius: var(--mld-radius-sm, 4px);
12180
+ letter-spacing: 0.02em;
12181
+ }
12182
+ .mld-exp-code--sm { padding: 1px 6px; font-size: 11px; }
12183
+ .mld-exp-code--md { padding: 2px 8px; font-size: 12px; }
12184
+ .mld-exp-code--lg { padding: 3px 10px; font-size: 14px; }
12051
12185
  /* BaseButton Component Styles */
12052
12186
  .mld-button {
12053
12187
  display: inline-flex;
@@ -12063,11 +12197,11 @@ html.dark .mld-settings-modal__option-btn--active {
12063
12197
  border: none;
12064
12198
  box-sizing: border-box;
12065
12199
  }
12066
- .mld-button:focus {
12200
+ .mld-button:focus-visible {
12067
12201
  outline: none;
12068
12202
  box-shadow: 0 0 0 2px white, 0 0 0 4px var(--color-primary);
12069
12203
  }
12070
- html.dark .mld-button:focus {
12204
+ html.dark .mld-button:focus-visible {
12071
12205
  box-shadow: 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--color-primary);
12072
12206
  }
12073
12207
  .mld-button--disabled {
@@ -12106,14 +12240,14 @@ html.dark .mld-button:focus {
12106
12240
  color: white;
12107
12241
  }
12108
12242
  .mld-button--danger:hover:not(.mld-button--disabled) {
12109
- background-color: #DC2626;
12243
+ background-color: var(--mld-error-hover);
12110
12244
  }
12111
12245
  .mld-button--success {
12112
12246
  background-color: var(--mld-success);
12113
12247
  color: white;
12114
12248
  }
12115
12249
  .mld-button--success:hover:not(.mld-button--disabled) {
12116
- background-color: #059669;
12250
+ background-color: var(--mld-success-hover);
12117
12251
  }
12118
12252
  .mld-button--ghost {
12119
12253
  background-color: transparent;
@@ -12214,6 +12348,9 @@ to {
12214
12348
  .mld-textarea::placeholder {
12215
12349
  color: var(--text-muted);
12216
12350
  }
12351
+ .mld-textarea:hover:not(:focus):not(.mld-textarea--disabled):not(.mld-textarea--error) {
12352
+ border-color: var(--text-muted);
12353
+ }
12217
12354
  .mld-textarea:focus {
12218
12355
  outline: none;
12219
12356
  border-color: transparent;
@@ -12226,7 +12363,7 @@ to {
12226
12363
  box-shadow: 0 0 0 2px var(--mld-error);
12227
12364
  }
12228
12365
  .mld-textarea--disabled {
12229
- opacity: 0.5;
12366
+ opacity: var(--mld-disabled-opacity);
12230
12367
  cursor: not-allowed;
12231
12368
  background-color: var(--bg-tertiary);
12232
12369
  }
@@ -12283,7 +12420,7 @@ to {
12283
12420
  box-shadow: 0 0 0 2px var(--mld-error);
12284
12421
  }
12285
12422
  .mld-select__control--disabled {
12286
- opacity: 0.5;
12423
+ opacity: var(--mld-disabled-opacity);
12287
12424
  cursor: not-allowed;
12288
12425
  background-color: var(--bg-tertiary);
12289
12426
  }
@@ -12640,7 +12777,7 @@ html.dark .mld-radio-option__native:focus-visible + .mld-radio-option__circle {
12640
12777
  gap: 12px;
12641
12778
  }
12642
12779
  .mld-slider--disabled {
12643
- opacity: 0.5;
12780
+ opacity: var(--mld-disabled-opacity);
12644
12781
  cursor: not-allowed;
12645
12782
  }
12646
12783
  .mld-slider__container {
@@ -12655,16 +12792,13 @@ html.dark .mld-radio-option__native:focus-visible + .mld-radio-option__circle {
12655
12792
  left: 0;
12656
12793
  right: 0;
12657
12794
  border-radius: 9999px;
12658
- background-color: #E2E8F0;
12659
- }
12660
- html.dark .mld-slider__track {
12661
- background-color: #334155;
12795
+ background-color: var(--bg-tertiary);
12662
12796
  }
12663
12797
  .mld-slider__fill {
12664
12798
  position: absolute;
12665
12799
  left: 0;
12666
12800
  border-radius: 9999px;
12667
- background-color: #3B82F6;
12801
+ background-color: var(--color-primary);
12668
12802
  }
12669
12803
  .mld-slider__input {
12670
12804
  position: absolute;
@@ -12685,7 +12819,7 @@ html.dark .mld-slider__track {
12685
12819
  transform: translateX(-50%) translateY(-50%);
12686
12820
  border-radius: 9999px;
12687
12821
  background-color: white;
12688
- border: 2px solid #3B82F6;
12822
+ border: 2px solid var(--color-primary);
12689
12823
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1);
12690
12824
  pointer-events: none;
12691
12825
  transition: transform 150ms ease;
@@ -12946,7 +13080,7 @@ html.dark .mld-slider__track {
12946
13080
  padding: 0 !important;
12947
13081
  }
12948
13082
  .mld-modal__close {
12949
- padding: 0.25rem;
13083
+ padding: 0.5rem;
12950
13084
  border-radius: var(--mld-radius-sm);
12951
13085
  color: var(--text-muted);
12952
13086
  background: none;
@@ -22891,6 +23025,140 @@ to { transform: rotate(360deg);
22891
23025
  padding-top: 1rem;
22892
23026
  border-top: 1px solid var(--color-border, #e5e7eb);
22893
23027
  }
23028
+ .mld-data-viewer {
23029
+ border: 1px solid var(--mld-color-border, #e0e0e0);
23030
+ border-radius: var(--mld-radius-md, 8px);
23031
+ overflow: hidden;
23032
+ }
23033
+ .mld-data-viewer__header {
23034
+ display: flex;
23035
+ align-items: center;
23036
+ justify-content: space-between;
23037
+ padding: 8px 12px;
23038
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
23039
+ background: var(--mld-color-surface-1, #fafafa);
23040
+ gap: 8px;
23041
+ }
23042
+ .mld-data-viewer__controls { display: flex; gap: 8px;
23043
+ }
23044
+ .mld-data-viewer__actions { display: flex; gap: 4px; align-items: center;
23045
+ }
23046
+ .mld-data-viewer__content {
23047
+ padding: 12px;
23048
+ max-height: 600px;
23049
+ overflow-y: auto;
23050
+ }
23051
+ .mld-data-viewer__loading,
23052
+ .mld-data-viewer__empty {
23053
+ text-align: center;
23054
+ padding: 32px;
23055
+ color: var(--mld-color-text-muted, #999);
23056
+ }
23057
+ /* Summary view */
23058
+ .mld-summary {
23059
+ display: flex;
23060
+ flex-direction: column;
23061
+ gap: 16px;
23062
+ }
23063
+ /* Metadata pills row */
23064
+ .mld-summary__metadata {
23065
+ display: flex;
23066
+ flex-wrap: wrap;
23067
+ gap: 6px;
23068
+ }
23069
+ .mld-summary__pill {
23070
+ display: inline-flex;
23071
+ align-items: center;
23072
+ border-radius: 6px;
23073
+ overflow: hidden;
23074
+ font-size: 0.8125rem;
23075
+ line-height: 1;
23076
+ border: 1px solid var(--mld-color-border, #e0e0e0);
23077
+ }
23078
+ .mld-summary__pill--sm {
23079
+ font-size: 0.75rem;
23080
+ }
23081
+ .mld-summary__pill-key {
23082
+ padding: 4px 8px;
23083
+ background: var(--mld-color-surface-1, #f5f5f5);
23084
+ color: var(--mld-color-text-muted, #666);
23085
+ text-transform: capitalize;
23086
+ font-weight: 500;
23087
+ }
23088
+ .mld-summary__pill-value {
23089
+ padding: 4px 8px;
23090
+ color: var(--mld-color-text, #1a1a1a);
23091
+ }
23092
+ /* Section */
23093
+ .mld-summary__section {
23094
+ display: flex;
23095
+ flex-direction: column;
23096
+ gap: 12px;
23097
+ }
23098
+ .mld-summary__section-label {
23099
+ font-weight: 600;
23100
+ font-size: 0.875rem;
23101
+ color: var(--mld-color-text, #1a1a1a);
23102
+ }
23103
+ .mld-summary__section-count {
23104
+ font-size: 0.75rem;
23105
+ color: var(--mld-color-text-muted, #999);
23106
+ margin-left: 8px;
23107
+ }
23108
+ .mld-summary__table-header {
23109
+ display: flex;
23110
+ align-items: baseline;
23111
+ gap: 4px;
23112
+ }
23113
+ /* Group cards */
23114
+ .mld-summary__group-card {
23115
+ border: 1px solid var(--mld-color-border, #e0e0e0);
23116
+ border-radius: var(--mld-radius-md, 8px);
23117
+ overflow: hidden;
23118
+ }
23119
+ .mld-summary__group-header {
23120
+ display: flex;
23121
+ align-items: center;
23122
+ justify-content: space-between;
23123
+ padding: 10px 14px;
23124
+ background: var(--mld-color-surface-1, #fafafa);
23125
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
23126
+ }
23127
+ .mld-summary__group-label {
23128
+ font-weight: 600;
23129
+ font-size: 0.875rem;
23130
+ color: var(--mld-color-text, #1a1a1a);
23131
+ }
23132
+ .mld-summary__group-count {
23133
+ font-size: 0.75rem;
23134
+ color: var(--mld-color-text-muted, #999);
23135
+ background: var(--mld-color-surface-2, #eee);
23136
+ padding: 2px 8px;
23137
+ border-radius: 10px;
23138
+ }
23139
+ .mld-summary__group-meta {
23140
+ display: flex;
23141
+ flex-wrap: wrap;
23142
+ gap: 6px;
23143
+ padding: 8px 14px;
23144
+ border-bottom: 1px solid var(--mld-color-border, #e0e0e0);
23145
+ }
23146
+ .mld-exp-code {
23147
+ display: inline-flex;
23148
+ align-items: center;
23149
+ font-family: var(--mld-font-mono, ui-monospace, monospace);
23150
+ font-weight: 600;
23151
+ background: var(--mld-color-surface-2, #f0f0f0);
23152
+ color: var(--mld-color-text-secondary, #666);
23153
+ border-radius: var(--mld-radius-sm, 4px);
23154
+ letter-spacing: 0.02em;
23155
+ }
23156
+ .mld-exp-code--sm { padding: 1px 6px; font-size: 11px;
23157
+ }
23158
+ .mld-exp-code--md { padding: 2px 8px; font-size: 12px;
23159
+ }
23160
+ .mld-exp-code--lg { padding: 3px 10px; font-size: 14px;
23161
+ }
22894
23162
  /* TimeRangeInput Component Styles */
22895
23163
  .mld-time-range {
22896
23164
  display: flex;
@@ -410,6 +410,29 @@ export interface ScheduleEventUpdateContext {
410
410
  newStart: Date;
411
411
  newEnd: Date;
412
412
  }
413
+ export interface SummarySectionItem {
414
+ label: string;
415
+ metadata?: Record<string, unknown>;
416
+ item_count: number;
417
+ item_key: string;
418
+ columns: string[];
419
+ rows: Record<string, unknown>[];
420
+ }
421
+ export interface SummarySection {
422
+ key: string;
423
+ label: string;
424
+ type: 'table' | 'group';
425
+ /** Group sections: list of group items with embedded tables */
426
+ items?: SummarySectionItem[];
427
+ /** Table sections: flat table columns and rows */
428
+ columns?: string[];
429
+ rows?: Record<string, unknown>[];
430
+ row_count?: number;
431
+ }
432
+ export interface SummaryData {
433
+ metadata: Record<string, unknown>;
434
+ sections: SummarySection[];
435
+ }
413
436
  export type ResourceStatus = 'available' | 'in-use' | 'maintenance' | 'offline';
414
437
  export interface ResourceSpec {
415
438
  label: string;
@@ -1,4 +1,4 @@
1
- export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, MoleculeData, StorageCondition, ReagentColumn, Reagent, TreeNodeType, BadgeVariant, TreeNode, } from './components';
1
+ export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, SummarySectionItem, SummarySection, SummaryData, ResourceStatus, ResourceSpec, MoleculeData, StorageCondition, ReagentColumn, Reagent, TreeNodeType, BadgeVariant, TreeNode, } from './components';
2
2
  export type { FormFieldType, FieldCondition, FieldValidation, FormFieldSchema, FormSectionSchema, FormStepSchema, FormSchema, FieldEnhancement, FormEnhancements, UseFormBuilderReturn, } from './form-builder';
3
3
  export type { AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, } from './auth';
4
4
  export type { PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformContextOptions, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './platform';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morscherlab/mld-sdk",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "MLD Platform SDK - Vue 3 components, composables, and types for plugin development",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -14,6 +14,7 @@ interface Props {
14
14
  min?: number
15
15
  max?: number
16
16
  step?: number
17
+ ariaDescribedby?: string
17
18
  }
18
19
 
19
20
  const props = withDefaults(defineProps<Props>(), {
@@ -52,6 +53,8 @@ function handleInput(event: Event) {
52
53
  :min="min"
53
54
  :max="max"
54
55
  :step="step"
56
+ :aria-invalid="error || undefined"
57
+ :aria-describedby="ariaDescribedby || undefined"
55
58
  :class="[
56
59
  'mld-input',
57
60
  `mld-input--${size}`,
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { watch, onMounted, onUnmounted } from 'vue'
2
+ import { ref, watch, nextTick, onMounted, onUnmounted } from 'vue'
3
3
  import type { ModalSize } from '../types'
4
4
 
5
5
  interface Props {
@@ -23,6 +23,49 @@ const emit = defineEmits<{
23
23
  close: []
24
24
  }>()
25
25
 
26
+ const containerRef = ref<HTMLElement | null>(null)
27
+ let previouslyFocused: HTMLElement | null = null
28
+
29
+ const FOCUSABLE_SELECTOR = [
30
+ 'a[href]',
31
+ 'button:not([disabled])',
32
+ 'input:not([disabled])',
33
+ 'select:not([disabled])',
34
+ 'textarea:not([disabled])',
35
+ '[tabindex]:not([tabindex="-1"])',
36
+ ].join(', ')
37
+
38
+ function getFocusableElements(): HTMLElement[] {
39
+ if (!containerRef.value) return []
40
+ return Array.from(containerRef.value.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR))
41
+ }
42
+
43
+ function handleKeydown(event: KeyboardEvent) {
44
+ if (event.key === 'Escape' && props.closeOnEscape && props.modelValue) {
45
+ close()
46
+ return
47
+ }
48
+
49
+ if (event.key !== 'Tab' || !containerRef.value) return
50
+
51
+ const focusable = getFocusableElements()
52
+ if (focusable.length === 0) {
53
+ event.preventDefault()
54
+ return
55
+ }
56
+
57
+ const first = focusable[0]
58
+ const last = focusable[focusable.length - 1]
59
+
60
+ if (event.shiftKey && document.activeElement === first) {
61
+ event.preventDefault()
62
+ last.focus()
63
+ } else if (!event.shiftKey && document.activeElement === last) {
64
+ event.preventDefault()
65
+ first.focus()
66
+ }
67
+ }
68
+
26
69
  function close() {
27
70
  if (props.closable) {
28
71
  emit('update:modelValue', false)
@@ -36,26 +79,30 @@ function handleOverlayClick(event: MouseEvent) {
36
79
  }
37
80
  }
38
81
 
39
- function handleEscape(event: KeyboardEvent) {
40
- if (props.closeOnEscape && event.key === 'Escape' && props.modelValue) {
41
- close()
42
- }
43
- }
44
-
45
- watch(() => props.modelValue, (isOpen) => {
82
+ watch(() => props.modelValue, async (isOpen) => {
46
83
  if (isOpen) {
84
+ previouslyFocused = document.activeElement as HTMLElement | null
47
85
  document.body.style.overflow = 'hidden'
86
+ await nextTick()
87
+ const focusable = getFocusableElements()
88
+ if (focusable.length > 0) {
89
+ focusable[0].focus()
90
+ } else {
91
+ containerRef.value?.focus()
92
+ }
48
93
  } else {
49
94
  document.body.style.overflow = ''
95
+ previouslyFocused?.focus()
96
+ previouslyFocused = null
50
97
  }
51
98
  })
52
99
 
53
100
  onMounted(() => {
54
- document.addEventListener('keydown', handleEscape)
101
+ document.addEventListener('keydown', handleKeydown)
55
102
  })
56
103
 
57
104
  onUnmounted(() => {
58
- document.removeEventListener('keydown', handleEscape)
105
+ document.removeEventListener('keydown', handleKeydown)
59
106
  document.body.style.overflow = ''
60
107
  })
61
108
  </script>
@@ -73,12 +120,14 @@ onUnmounted(() => {
73
120
 
74
121
  <!-- Modal -->
75
122
  <div
123
+ ref="containerRef"
76
124
  :class="[
77
125
  'mld-modal__container',
78
126
  `mld-modal__container--${size}`,
79
127
  ]"
80
128
  role="dialog"
81
129
  aria-modal="true"
130
+ tabindex="-1"
82
131
  >
83
132
  <!-- Header -->
84
133
  <div v-if="title || closable" class="mld-modal__header">
@@ -8,6 +8,7 @@ interface Props {
8
8
  disabled?: boolean
9
9
  error?: boolean
10
10
  size?: 'sm' | 'md' | 'lg'
11
+ ariaDescribedby?: string
11
12
  }
12
13
 
13
14
  const props = withDefaults(defineProps<Props>(), {
@@ -34,6 +35,8 @@ function handleChange(event: Event) {
34
35
  <select
35
36
  :value="modelValue"
36
37
  :disabled="disabled"
38
+ :aria-invalid="error || undefined"
39
+ :aria-describedby="ariaDescribedby || undefined"
37
40
  :class="[
38
41
  'mld-select__control',
39
42
  `mld-select__control--${size}`,