webcake-ui-kit 1.1.13 → 1.1.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webcake-ui-kit",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "description": "UI Kit for Vue 2 && 3 - Pure Options API",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -94,6 +94,7 @@
94
94
 
95
95
  <script>
96
96
  import { acquire, release } from '../../floating/portal-root.js'
97
+ import { bumpTo } from '../../floating/layer-manager.js'
97
98
  import Button from '../button/Button.vue'
98
99
  import WkiMinus from '../../icons/Minus.vue'
99
100
  import WkiUnfoldVertical from '../../icons/UnfoldVertical.vue'
@@ -257,6 +258,7 @@ export default {
257
258
  },
258
259
  onOpen() {
259
260
  this.hasOpened = true
261
+ bumpTo(this.zIndex)
260
262
  this.lockBody()
261
263
  if (typeof document !== 'undefined') {
262
264
  this._prevFocus = document.activeElement
@@ -5,12 +5,12 @@
5
5
  <slot name="media"></slot>
6
6
  </div>
7
7
  <div v-if="hasTextBlock" class="ui-empty__text">
8
- <p v-if="hasTitle" class="ui-empty__title">
8
+ <Typography v-if="hasTitle" variant="paragraph" weight="medium">
9
9
  <slot name="title">{{ title }}</slot>
10
- </p>
11
- <p v-if="hasDescription" class="ui-empty__description">
10
+ </Typography>
11
+ <Typography v-if="hasDescription" variant="paragraph-small" weight="regular">
12
12
  <slot name="description">{{ description }}</slot>
13
- </p>
13
+ </Typography>
14
14
  </div>
15
15
  <div v-if="hasFooter" class="ui-empty__footer">
16
16
  <slot></slot>
@@ -20,8 +20,11 @@
20
20
  </template>
21
21
 
22
22
  <script>
23
+ import Typography from '../typography/Typography.vue'
24
+
23
25
  export default {
24
26
  name: 'Empty',
27
+ components: { Typography },
25
28
  props: {
26
29
  variant: {
27
30
  type: String,
@@ -49,26 +49,6 @@
49
49
  width: 100%;
50
50
  }
51
51
 
52
- .ui-empty__title {
53
- margin: 0;
54
- font-family: var(--font-family-body);
55
- font-size: var(--paragraph-regular-font-size);
56
- line-height: var(--paragraph-regular-line-height);
57
- letter-spacing: var(--paragraph-regular-letter-spacing);
58
- font-weight: var(--paragraph-medium-font-weight);
59
- color: var(--primary-fg);
60
- }
61
-
62
- .ui-empty__description {
63
- margin: 0;
64
- font-family: var(--font-family-body);
65
- font-size: var(--paragraph-small-font-size);
66
- line-height: var(--paragraph-small-line-height);
67
- letter-spacing: var(--paragraph-small-letter-spacing);
68
- font-weight: var(--paragraph-font-weight);
69
- color: var(--muted-fg);
70
- }
71
-
72
52
  /* Footer slot — stacks action group(s) below the text block.
73
53
  Consumer composes button rows / link rows freely; gap matches the
74
54
  outer content stack so a single child OR multiple children line up. */
@@ -17,6 +17,7 @@
17
17
  class="ui-input-number__field"
18
18
  type="text"
19
19
  inputmode="decimal"
20
+ :style="centered ? { textAlign: 'center' } : {}"
20
21
  :value="displayValue"
21
22
  :placeholder="placeholder"
22
23
  :disabled="disabled"
@@ -59,7 +60,8 @@ export default {
59
60
  default: 'default',
60
61
  validator: v => ['default', 'round'].includes(v)
61
62
  },
62
- error: { type: Boolean, default: false }
63
+ error: { type: Boolean, default: false },
64
+ centered: { type: Boolean, default: false }
63
65
  },
64
66
  emits: ['input', 'update:modelValue', 'change', 'focus', 'blur', 'pressEnter'],
65
67
  data() {
@@ -88,6 +88,7 @@
88
88
  :disabled="opt.disabled"
89
89
  />
90
90
  </slot>
91
+ <Empty v-if="showEmpty" description="No data" />
91
92
  </div>
92
93
  </Menu>
93
94
  </template>
@@ -98,11 +99,12 @@ import Menu from '../menu/Menu.vue'
98
99
  import SelectOption from '../select-option/SelectOption.vue'
99
100
  import Spinner from '../spinner/Spinner.vue'
100
101
  import Tag from '../tag/Tag.vue'
102
+ import Empty from '../empty/Empty.vue'
101
103
 
102
104
  export default {
103
105
  name: 'Select',
104
106
 
105
- components: { Menu, SelectOption, Spinner, WkiChevronDown, Tag },
107
+ components: { Menu, SelectOption, Spinner, WkiChevronDown, Tag, Empty },
106
108
 
107
109
  provide() {
108
110
  return { select: this }
@@ -180,7 +182,8 @@ export default {
180
182
  isOpen: false,
181
183
  labelCache: {},
182
184
  filterText: '',
183
- tagOptions: []
185
+ tagOptions: [],
186
+ slotOptionVisible: {}
184
187
  }
185
188
  },
186
189
 
@@ -243,6 +246,14 @@ export default {
243
246
  return { value: v, label: opt ? opt.label : self.labelCache[v] || v }
244
247
  })
245
248
  },
249
+ showEmpty() {
250
+ if (this.normalizedOptions.length > 0 && this.filteredOptions.length === 0) return true
251
+ if (this.filterText) {
252
+ var vals = Object.keys(this.slotOptionVisible)
253
+ if (vals.length > 0 && vals.every(v => !this.slotOptionVisible[v])) return true
254
+ }
255
+ return false
256
+ },
246
257
  hasIconSlot() {
247
258
  return !!((this.$scopedSlots && this.$scopedSlots['icon']) || this.$slots['icon'])
248
259
  },
@@ -287,6 +298,7 @@ export default {
287
298
  onSearchKeydown(e) {
288
299
  if (e.key === 'Enter') {
289
300
  e.preventDefault()
301
+ if (e.isComposing) return
290
302
  if (this.mode === 'tags' && this.filterText.trim()) {
291
303
  const text = this.filterText.trim()
292
304
  const existing = this.normalizedOptions.find(function (o) {
@@ -364,6 +376,14 @@ export default {
364
376
  registerOption(value, label) {
365
377
  this.labelCache = Object.assign({}, this.labelCache, { [value]: label })
366
378
  },
379
+ setSlotOptionVisible(value, visible) {
380
+ this.slotOptionVisible = Object.assign({}, this.slotOptionVisible, { [value]: visible })
381
+ },
382
+ removeSlotOption(value) {
383
+ var next = Object.assign({}, this.slotOptionVisible)
384
+ delete next[value]
385
+ this.slotOptionVisible = next
386
+ },
367
387
  _slotNodes() {
368
388
  // Vue 3: $slots.default is a function; Vue 2: it's an array
369
389
  return typeof this.$slots.default === 'function' ? this.$slots.default() : this.$slots.default || []
@@ -228,7 +228,6 @@
228
228
  flex-direction: column;
229
229
  overflow-y: auto;
230
230
  padding: var(--spacing-2xs);
231
- scrollbar-width: thin;
232
231
  gap: var(--spacing-3xs);
233
232
  }
234
233
 
@@ -240,3 +239,7 @@
240
239
  background: var(--border-primary);
241
240
  border-radius: 3px;
242
241
  }
242
+
243
+ .ui-select__empty {
244
+ padding: var(--spacing-sm) var(--spacing-xs);
245
+ }
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <div
3
+ v-show="!isHidden"
3
4
  class="ui-select-option"
4
5
  :class="[
5
6
  size === 'large' ? 'ui-select-option--large' : null,
@@ -12,14 +13,22 @@
12
13
  :aria-disabled="isDisabled ? 'true' : null"
13
14
  @click="handleClick"
14
15
  >
15
- <slot>{{ label || value }}</slot>
16
+ <span class="ui-select-option--label">
17
+ <slot>{{ label || value }}</slot>
18
+ </span>
19
+ <WkiCheck v-if="isSelected" :size="16" color="var(--muted-fg)" />
16
20
  </div>
17
21
  </template>
18
22
 
19
23
  <script>
24
+ import { WkiCheck } from '../../icons'
20
25
  export default {
21
26
  name: 'SelectOption',
22
27
 
28
+ components: {
29
+ WkiCheck
30
+ },
31
+
23
32
  inject: {
24
33
  select: { default: null }
25
34
  },
@@ -55,7 +64,35 @@ export default {
55
64
 
56
65
  emits: [],
57
66
 
67
+ mounted() {
68
+ this._registerLabel()
69
+ if (this.select) this.select.setSlotOptionVisible(this.value, !this.isHidden)
70
+ },
71
+
72
+ updated() {
73
+ this._registerLabel()
74
+ },
75
+
76
+ beforeUnmount() {
77
+ if (this.select) this.select.removeSlotOption(this.value)
78
+ },
79
+
80
+ watch: {
81
+ isHidden(val) {
82
+ if (this.select) this.select.setSlotOptionVisible(this.value, !val)
83
+ }
84
+ },
85
+
58
86
  computed: {
87
+ isHidden() {
88
+ if (!this.select || !this.select.filterText) return false
89
+ var q = this.select.filterText.toLowerCase()
90
+ var label = (this.select.labelCache && this.select.labelCache[this.value]) || this.label || String(this.value)
91
+ if (typeof this.select.filterOption === 'function') {
92
+ return !this.select.filterOption(this.select.filterText, { label: label, value: this.value })
93
+ }
94
+ return label.toLowerCase().indexOf(q) === -1
95
+ },
59
96
  isSelected() {
60
97
  if (!this.select) return false
61
98
  var val = this.select.effectiveValue
@@ -70,6 +107,13 @@ export default {
70
107
  },
71
108
 
72
109
  methods: {
110
+ _registerLabel() {
111
+ if (!this.select) return
112
+ var labelEl = this.$el && this.$el.querySelector('.ui-select-option--label')
113
+ var slotText = labelEl ? labelEl.textContent.trim() : ''
114
+ var labelText = slotText || this.label || String(this.value)
115
+ this.select.registerOption(this.value, labelText)
116
+ },
73
117
  handleClick() {
74
118
  if (this.isDisabled) return
75
119
  if (this.select && typeof this.select.select === 'function') {
@@ -58,3 +58,11 @@
58
58
  background: transparent;
59
59
  box-shadow: 0 0 0 3px var(--ring);
60
60
  }
61
+
62
+ .ui-select-option--label {
63
+ flex: 1 1 0;
64
+ min-width: 0;
65
+ overflow: hidden;
66
+ text-overflow: ellipsis;
67
+ white-space: nowrap;
68
+ }
@@ -8,7 +8,8 @@
8
8
  'ui-sidebar-item--level-2': level === 2,
9
9
  'ui-sidebar-item--has-children': hasChildren,
10
10
  'ui-sidebar-item--expanded': hasChildren && expanded,
11
- 'ui-sidebar-item--collapsed': collapsed
11
+ 'ui-sidebar-item--collapsed': collapsed,
12
+ 'ui-sidebar-item--icon-only': isIconOnly
12
13
  }"
13
14
  :tabindex="disabled ? -1 : 0"
14
15
  :aria-current="active ? 'page' : undefined"
@@ -19,7 +20,7 @@
19
20
  <span v-if="hasIconSlot" class="ui-sidebar-item__icon" aria-hidden="true">
20
21
  <slot name="icon" />
21
22
  </span>
22
- <span class="ui-sidebar-item__label">
23
+ <span class="ui-sidebar-item__label" v-if="hasDefaultSlot || label">
23
24
  <slot>{{ label }}</slot>
24
25
  </span>
25
26
  <span v-if="badge" class="ui-sidebar-item__badge">{{ badge }}</span>
@@ -96,6 +97,12 @@ export default {
96
97
  },
97
98
  hasIconRightSlot() {
98
99
  return !!((this.$scopedSlots && this.$scopedSlots['icon-right']) || this.$slots['icon-right'])
100
+ },
101
+ hasDefaultSlot() {
102
+ return !!this.$slots['default']
103
+ },
104
+ isIconOnly() {
105
+ return !this.label && !this.hasDefaultSlot && this.hasIconSlot
99
106
  }
100
107
  },
101
108
 
@@ -53,6 +53,19 @@
53
53
  font-size: 15px;
54
54
  }
55
55
 
56
+ .ui-sidebar-item--icon-only {
57
+ width: 32px;
58
+ height: 32px;
59
+ padding: var(--spacing-2xs);
60
+ justify-content: center;
61
+ }
62
+
63
+ .ui-sidebar-item--large.ui-sidebar-item--icon-only {
64
+ width: 36px;
65
+ height: 36px;
66
+ padding: var(--spacing-xs);
67
+ }
68
+
56
69
  /* Level 2 — nested, indented */
57
70
  .ui-sidebar-item--level-2 {
58
71
  padding-left: var(--spacing-lg);
@@ -32,6 +32,7 @@
32
32
 
33
33
  <script>
34
34
  import { acquire, release } from '../../floating/portal-root.js'
35
+ import { nextZIndex } from '../../floating/layer-manager.js'
35
36
 
36
37
  const GAP = 4
37
38
 
@@ -137,7 +138,7 @@ export default {
137
138
  position: 'fixed',
138
139
  top: top + 'px',
139
140
  left: left + 'px',
140
- zIndex: 1050
141
+ zIndex: nextZIndex()
141
142
  }
142
143
  },
143
144
  cleanup() {
@@ -16,6 +16,14 @@ export function currentZIndex() {
16
16
  return _counter
17
17
  }
18
18
 
19
+ // Ensure subsequent nextZIndex() calls return values above `n`.
20
+ // Call this when a layer (e.g. Dialog) opens with an explicit z-index so that
21
+ // floating panels inside it always land on top.
22
+ export function bumpTo(n) {
23
+ const v = Number(n)
24
+ if (!isNaN(v) && v > _counter) _counter = v
25
+ }
26
+
19
27
  // Test helper — reset between specs.
20
28
  export function _reset() {
21
29
  _counter = BASE
@@ -0,0 +1,42 @@
1
+ <template>
2
+ <BaseIcon v-bind="$attrs" v-on="listeners">
3
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
4
+ <path
5
+ d="M11.0127 3.1592C11.4354 3.15928 11.7711 3.47887 11.7715 3.88088C11.7712 4.28295 11.4354 4.60347 11.0127 4.60354H4.5332C3.97403 4.60386 3.51894 5.03648 3.51855 5.56838V16.4229C3.51882 16.6786 3.6263 16.9247 3.81641 17.1055C4.00655 17.2861 4.26448 17.3876 4.5332 17.3877H7.19434C7.61726 17.3878 7.9541 17.709 7.9541 18.1114V19.9746L12.1533 17.4932C12.2732 17.4233 12.4153 17.3878 12.5586 17.3877H18.5967C19.0339 17.3877 19.4044 17.1224 19.5469 16.753H19.626V13.6319C19.626 13.2296 19.9619 12.9093 20.3848 12.9092C20.8077 12.9092 21.1445 13.2295 21.1445 13.6319V16.4229C21.144 17.7476 20.0146 18.833 18.6104 18.833H12.8008L12.7168 18.8819L7.61328 21.8936C7.49342 21.9636 7.35241 21.9999 7.20898 22H7.2041C7.10381 22.0011 7.00318 21.9839 6.91016 21.9483C6.81741 21.9126 6.73238 21.8598 6.66113 21.793C6.58975 21.7259 6.53287 21.6438 6.49414 21.5557C6.45572 21.4679 6.43559 21.3735 6.43555 21.2783V18.833H4.5332C3.14078 18.8327 2.00053 17.7583 2 16.4229V5.56838C2.00039 4.24476 3.14176 3.15952 4.5332 3.1592H11.0127Z"
6
+ fill="currentColor"
7
+ />
8
+ <path
9
+ d="M6.9209 10.3262C7.38785 10.3264 7.76657 10.6998 7.7666 11.1602C7.7666 11.6206 7.38787 11.994 6.9209 11.9942C6.45378 11.9942 6.0752 11.6207 6.0752 11.1602C6.07523 10.6997 6.4538 10.3262 6.9209 10.3262Z"
10
+ fill="currentColor"
11
+ />
12
+ <path
13
+ d="M11.9951 10.3262C12.4622 10.3262 12.8408 10.6997 12.8408 11.1602C12.8408 11.6207 12.4622 11.9942 11.9951 11.9942C11.5281 11.994 11.1494 11.6206 11.1494 11.1602C11.1495 10.6998 11.5281 10.3263 11.9951 10.3262Z"
14
+ fill="currentColor"
15
+ />
16
+ <path
17
+ d="M16.2246 10.3262C16.6916 10.3263 17.0703 10.6998 17.0703 11.1602C17.0703 11.6206 16.6916 11.994 16.2246 11.9942C15.7575 11.9942 15.3789 11.6207 15.3789 11.1602C15.3789 10.6997 15.7575 10.3262 16.2246 10.3262Z"
18
+ fill="currentColor"
19
+ />
20
+ <path
21
+ d="M18.2188 2.41116C18.4376 1.86298 19.2538 1.86299 19.4727 2.41116L20.2197 4.27444C20.2891 4.44691 20.428 4.57858 20.6094 4.64456L22.5674 5.35549C23.1437 5.56362 23.1437 6.33976 22.5674 6.54788L20.6094 7.25881C20.4279 7.32481 20.2891 7.45732 20.2197 7.62991L19.4727 9.49221C19.2539 10.0405 18.4376 10.0405 18.2188 9.49221L17.4717 7.62991C17.4023 7.45732 17.2634 7.32481 17.082 7.25881L15.124 6.54788C14.5478 6.33976 14.5478 5.56362 15.124 5.35549L17.082 4.64456C17.2633 4.57858 17.4023 4.44694 17.4717 4.27444L18.2188 2.41116Z"
22
+ fill="currentColor"
23
+ />
24
+ </svg>
25
+ </BaseIcon>
26
+ </template>
27
+
28
+ <script>
29
+ import BaseIcon from './BaseIcon.vue'
30
+
31
+ export default {
32
+ name: 'GeneratePrompt',
33
+ components: { BaseIcon },
34
+ inheritAttrs: false,
35
+ emits: [],
36
+ computed: {
37
+ listeners() {
38
+ return this.$listeners || {}
39
+ }
40
+ }
41
+ }
42
+ </script>
@@ -1735,4 +1735,5 @@ export { default as WkiLayersUp } from './LayersUp.vue'
1735
1735
  export { default as WkiLayersDown } from './LayersDown.vue'
1736
1736
  export { default as WkiLayersUpToTop } from './LayersUpToTop.vue'
1737
1737
  export { default as WkiLayersDownToBottom } from './LayersDownToBottom.vue'
1738
+ export { default as WkiGeneratePrompt } from './GeneratePrompt.vue'
1738
1739
  // --- AUTO-GENERATED LUCIDE EXPORTS END ---