@nexxtmove/ui 2.3.0 → 2.5.0

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "2.3.0",
4
+ "version": "2.5.0",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -110,9 +110,9 @@ const selected = computed({
110
110
  <template>
111
111
  <NexxtEditorSettingsBlock :label="label">
112
112
  <!--
113
- Select is `inline-flex` and its field carries a `min-w-60`, so without
114
- `w-full` it would sit at that minimum instead of filling the block. The
115
- class lands on Select's root, whose trigger is already `w-full`.
113
+ Select is `inline-flex` and 240px wide by default (capped at its
114
+ container), so without `w-full` it would sit at 240px instead of filling
115
+ the block. The class lands on Select's root; the trigger grows with it.
116
116
  -->
117
117
  <!--
118
118
  The block label is a <p>, not a <label>, so the combobox would have no
@@ -151,7 +151,7 @@ watch(model, () => {
151
151
  </script>
152
152
 
153
153
  <template>
154
- <div class="inline-flex flex-col gap-1">
154
+ <div class="inline-flex flex-col gap-1 [:where(&)]:max-w-full">
155
155
  <label v-if="label" class="justify-start small-normal text-gray-700" :for="selectId">
156
156
  {{ label }}
157
157
  <span v-if="required" class="text-brick-500">*</span>
@@ -165,6 +165,10 @@ watch(model, () => {
165
165
  @open="activeIndex = selectedIndex >= 0 ? selectedIndex : activeIndex"
166
166
  >
167
167
  <template #trigger="{ isOpen, toggle }">
168
+ <!-- The 240px default width lives here, as the trigger's flex basis: it
169
+ holds in a shrink-to-fit wrapper, and the trigger shrinks below it
170
+ (min-w-0) or grows past it with any width the root gets. The root's
171
+ max-w-full, at zero specificity, keeps it inside a narrow column. -->
168
172
  <div
169
173
  :id="selectId"
170
174
  role="combobox"
@@ -174,7 +178,7 @@ watch(model, () => {
174
178
  :aria-controls="isOpen ? listboxId : undefined"
175
179
  :aria-activedescendant="isOpen && activeIndex >= 0 ? optionId(activeIndex) : undefined"
176
180
  tabindex="0"
177
- class="group flex w-full cursor-pointer items-center gap-2 rounded-lg ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
181
+ class="group flex w-60 min-w-0 grow cursor-pointer items-center gap-2 rounded-lg ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
178
182
  :class="[
179
183
  error ? 'ring-brick-400' : 'ring-gray-200',
180
184
  { 'pl-3': triggerIcon, 'pr-3': true },
@@ -185,11 +189,13 @@ watch(model, () => {
185
189
  <span v-if="triggerIcon" class="flex items-center">
186
190
  <NexxtIcon :name="triggerIcon" />
187
191
  </span>
192
+ <!-- The ellipsis needs a block box: text directly in a flex container is
193
+ an anonymous flex item that `truncate` does not reach. -->
188
194
  <span
189
- class="flex h-10 w-full min-w-60 items-center text-sm"
195
+ class="flex h-10 min-w-0 flex-1 items-center text-sm"
190
196
  :class="[selectedLabel ? 'text-gray-900' : 'text-gray-400', { 'pl-3': !triggerIcon }]"
191
197
  >
192
- {{ selectedLabel ?? placeholder }}
198
+ <span class="truncate">{{ selectedLabel ?? placeholder }}</span>
193
199
  </span>
194
200
  <NexxtIcon
195
201
  name="chevron-down"
@@ -71,7 +71,7 @@ const onOpen = async () => {
71
71
  </script>
72
72
 
73
73
  <template>
74
- <div class="inline-flex flex-col gap-1">
74
+ <div class="inline-flex flex-col gap-1 [:where(&)]:max-w-full">
75
75
  <label v-if="label" class="justify-start small-normal text-gray-700" :for="selectId">
76
76
  {{ label }}
77
77
  <span v-if="required" class="text-brick-500">*</span>
@@ -79,20 +79,24 @@ const onOpen = async () => {
79
79
 
80
80
  <NexxtFloatingPanel placement="bottom" match-width @open="onOpen">
81
81
  <template #trigger="{ isOpen, toggle }">
82
+ <!-- The 240px default width lives here, as the trigger's flex basis: it
83
+ holds in a shrink-to-fit wrapper, and the trigger shrinks below it
84
+ (min-w-0) or grows past it with any width the root gets. The root's
85
+ max-w-full, at zero specificity, keeps it inside a narrow column. -->
82
86
  <div
83
87
  :id="selectId"
84
88
  role="combobox"
85
89
  :aria-expanded="isOpen"
86
90
  aria-haspopup="listbox"
87
91
  tabindex="0"
88
- class="group flex w-full cursor-pointer items-center gap-2 rounded-lg pr-3 ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
92
+ class="group flex w-60 min-w-0 grow cursor-pointer items-center gap-2 rounded-lg pr-3 ring transition-colors ease-out focus:ring-cornflower-blue-500 focus:outline-none"
89
93
  :class="error ? 'ring-brick-400' : 'ring-gray-200'"
90
94
  @click="toggle"
91
95
  @keydown.enter.prevent="toggle"
92
96
  @keydown.space.prevent="toggle"
93
97
  >
94
98
  <span
95
- class="flex h-10 w-full min-w-60 items-center gap-2 pl-3 text-sm"
99
+ class="flex h-10 min-w-0 flex-1 items-center gap-2 pl-3 text-sm"
96
100
  :class="selectedCountry ? 'text-gray-900' : 'text-gray-400'"
97
101
  >
98
102
  <span
@@ -100,7 +104,8 @@ const onOpen = async () => {
100
104
  :class="`fi fi-${selectedCountry.code}`"
101
105
  class="shrink-0"
102
106
  />
103
- {{ selectedCountry?.name ?? placeholder }}
107
+ <!-- A block box of its own, or `truncate` would not reach the text. -->
108
+ <span class="truncate">{{ selectedCountry?.name ?? placeholder }}</span>
104
109
  </span>
105
110
  <NexxtIcon
106
111
  name="chevron-down"
@@ -54,9 +54,16 @@ export interface NexxtVideoControlsProps {
54
54
  fullscreenTarget?: HTMLElement | null
55
55
  /**
56
56
  * `full`: the bar; `toggle`: a 32px play/pause button in the corner, with mute to its left on
57
- * hover, focus or a tap. Both hide while playing by the same rules. Defaults to `full`.
57
+ * hover, focus or a tap (see `showMute`). Both hide while playing by the same rules. Defaults
58
+ * to `full`.
58
59
  */
59
60
  variant?: NexxtVideoControlsVariant
61
+ /**
62
+ * Toggle only: the mute button left of play/pause. Off leaves play/pause alone in the corner,
63
+ * e.g. for a background video that is always muted and may only be paused. The `full` bar
64
+ * ignores it. Defaults to `true`.
65
+ */
66
+ showMute?: boolean
60
67
  /** The video's name, for the name of the bar (or of the toggle's buttons). */
61
68
  name?: string
62
69
  /** Hide the bar (or the toggle) after inactivity while the video plays. Off keeps it on show. Defaults to `true`. */
@@ -81,6 +88,7 @@ const {
81
88
  target,
82
89
  fullscreenTarget = null,
83
90
  variant = 'full',
91
+ showMute = true,
84
92
  name = '',
85
93
  autoHide = true,
86
94
  hideDelay = 2500,
@@ -583,9 +591,11 @@ const onVideoClick = () => {
583
591
  return
584
592
  }
585
593
 
586
- // A tap toggles what touch cannot hover for: the bar, or the toggle's mute button
594
+ // A tap toggles what touch cannot hover for: the bar, or the toggle's mute button. A toggle
595
+ // without one is a bar of one button: the tap toggles the toggle itself
587
596
  clearTimeout(touchTimer)
588
- touchShown.value = !(variant === 'toggle' ? toggleMuteShown.value : visible.value)
597
+ const tapRevealsMute = variant === 'toggle' && showMute
598
+ touchShown.value = !(tapRevealsMute ? toggleMuteShown.value : visible.value)
589
599
  if (touchShown.value) {
590
600
  touchTimer = setTimeout(() => {
591
601
  touchShown.value = false
@@ -747,7 +757,7 @@ onBeforeUnmount(() => {
747
757
  The corner buttons: play/pause in the corner, and mute to its left on hover, focus or a tap
748
758
  (DOM and tab order follow what is seen: mute, then play). Mute is transparent when hidden,
749
759
  never removed, so play keeps its place and both stay in the tab order. Both fade with the
750
- same rules as the bar.
760
+ same rules as the bar. Without `showMute` there is no mute at all; play stays in the corner.
751
761
  -->
752
762
  <div
753
763
  ref="capsule"
@@ -762,6 +772,7 @@ onBeforeUnmount(() => {
762
772
  @keydown="onKeyInside"
763
773
  >
764
774
  <button
775
+ v-if="showMute"
765
776
  type="button"
766
777
  :aria-label="toggleMuteLabel"
767
778
  class="group/mute flex cursor-pointer rounded-full bg-black/50 small-normal text-white ring-1 ring-white/30 backdrop-blur-xs transition-opacity focus-visible:ring-2 focus-visible:ring-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 motion-reduce:transition-none"