@nexxtmove/ui 1.14.0 → 1.15.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/dist/nuxt.js CHANGED
@@ -63,7 +63,8 @@ var s = {
63
63
  NexxtTimelinePhaseblock: "components/organisms/TimelinePhaseblock/TimelinePhaseblock.vue",
64
64
  NexxtTimelineTrack: "components/organisms/TimelineTrack/TimelineTrack.vue",
65
65
  NexxtToaster: "components/organisms/Toaster/Toaster.vue",
66
- NexxtVideoPlayer: "components/organisms/VideoPlayer/VideoPlayer.vue"
66
+ NexxtVideoPlayer: "components/organisms/VideoPlayer/VideoPlayer.vue",
67
+ NexxtEditorSettingsBlock: "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue"
67
68
  }, c = ["@nexxtmove/ui/ui.css", "@nexxtmove/ui/dist/ui.css"], l = (e, t) => e.some((e) => e === t || c.includes(e)), u = i({
68
69
  meta: {
69
70
  name: "@nexxtmove/ui",
@@ -85,8 +86,8 @@ var s = {
85
86
  });
86
87
  let d = u("./assets");
87
88
  if (a(d)) {
88
- let e = `/${[c.options.app.buildAssetsDir, "assets"].join("/").replace(/\/+/g, "/").replace(/^\/|\/$/g, "")}/`;
89
- c.options.nitro.publicAssets ??= [], c.options.nitro.publicAssets.push({
89
+ let e = `/${[c.options.app.buildAssetsDir, "assets"].join("/").replace(/\/+/g, "/").replace(/^\/|\/$/g, "")}/`, t = c.options;
90
+ t.nitro.publicAssets ??= [], t.nitro.publicAssets.push({
90
91
  dir: d,
91
92
  baseURL: e,
92
93
  maxAge: 31536e3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nexxtmove/ui",
3
3
  "type": "module",
4
- "version": "1.14.0",
4
+ "version": "1.15.0",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",
@@ -37,12 +37,12 @@
37
37
  "@eslint/js": "^10.0.1",
38
38
  "@nuxt/kit": "^4.5.2",
39
39
  "@nuxt/schema": "^4.5.2",
40
- "@storybook/addon-a11y": "^10.5.10",
40
+ "@storybook/addon-a11y": "^10.6.0",
41
41
  "@storybook/addon-designs": "^11.1.4",
42
- "@storybook/addon-docs": "^10.5.10",
43
- "@storybook/addon-vitest": "^10.5.10",
44
- "@storybook/builder-vite": "^10.5.10",
45
- "@storybook/vue3-vite": "^10.5.10",
42
+ "@storybook/addon-docs": "^10.6.0",
43
+ "@storybook/addon-vitest": "^10.6.0",
44
+ "@storybook/builder-vite": "^10.6.0",
45
+ "@storybook/vue3-vite": "^10.6.0",
46
46
  "@tailwindcss/vite": "^4.3.3",
47
47
  "@types/node": "^26.2.0",
48
48
  "@types/react": "^19.2.18",
@@ -59,7 +59,7 @@
59
59
  "eslint-config-prettier": "^10.1.8",
60
60
  "eslint-plugin-better-tailwindcss": "4.7.0",
61
61
  "eslint-plugin-prettier": "^5.5.6",
62
- "eslint-plugin-storybook": "10.5.10",
62
+ "eslint-plugin-storybook": "10.6.0",
63
63
  "eslint-plugin-vue": "^10.10.0",
64
64
  "flag-icons": "^7.5.0",
65
65
  "globals": "^17.11.0",
@@ -70,7 +70,7 @@
70
70
  "react": "^19.2.8",
71
71
  "react-dom": "^19.2.8",
72
72
  "remark-frontmatter": "^5.0.0",
73
- "storybook": "^10.5.10",
73
+ "storybook": "^10.6.0",
74
74
  "typescript-eslint": "^8.67.0",
75
75
  "vite": "^8.2.1",
76
76
  "vite-plugin-dts": "^5.0.3",
@@ -61,11 +61,18 @@ const iconSizeClasses: Record<SwitchSize, string> = {
61
61
  <template>
62
62
  <label class="inline-flex cursor-pointer items-center gap-2">
63
63
  <slot v-if="labelPosition === 'before'" />
64
- <span :class="['relative inline-block', trackClasses[size]]">
64
+ <!--
65
+ `shrink-0`: the track has a fixed pixel size, so letting flex shrink it
66
+ squashes the toggle the moment a sibling label wraps onto a second line.
67
+ -->
68
+ <span :class="['relative inline-block shrink-0', trackClasses[size]]">
65
69
  <input v-bind="$attrs" type="checkbox" class="peer sr-only" v-model="model" />
66
70
  <span
67
71
  :class="[
68
72
  'absolute inset-0 overflow-hidden rounded-[30px] border transition-colors duration-200',
73
+ // The input is `sr-only`, so the track has to render the focus ring.
74
+ // `outline` draws outside the box and is not clipped by `overflow-hidden`.
75
+ 'peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-cornflower-blue-500',
69
76
  model ? checkedColorClasses[color] : 'border-gray-500 bg-gray-200',
70
77
  ]"
71
78
  >
@@ -0,0 +1,83 @@
1
+ <script lang="ts" setup>
2
+ import { computed } from 'vue'
3
+ import Switch from '../../../atoms/Switch/Switch.vue'
4
+
5
+ interface NexxtEditorSettingsBlockProps {
6
+ /** Header text of the block. Wraps over multiple lines when it is too long. */
7
+ label: string
8
+ /**
9
+ * Render a switch next to the label that collapses and expands the content.
10
+ * When `false` the content is always visible and the model is ignored.
11
+ */
12
+ switchable?: boolean
13
+ }
14
+
15
+ defineOptions({ name: 'NexxtEditorSettingsBlock' })
16
+
17
+ const { label, switchable = false } = defineProps<NexxtEditorSettingsBlockProps>()
18
+
19
+ /**
20
+ * Open state of the block, driven by the switch. Only has an effect when
21
+ * `switchable` is `true`; the parent owns the state.
22
+ */
23
+ const model = defineModel<boolean>({ default: true })
24
+
25
+ const open = computed(() => !switchable || model.value)
26
+
27
+ // Vue only drops an attribute on `false` for a fixed list of boolean
28
+ // attributes, and `inert` is not on that list: `:inert="false"` renders
29
+ // `inert="false"`, which a browser still treats as inert. `undefined` is the
30
+ // only value that removes the attribute again.
31
+ const inert = computed(() => (open.value ? undefined : true))
32
+ </script>
33
+
34
+ <template>
35
+ <div class="border-b border-gray-200 py-4 last:border-b-0">
36
+ <!--
37
+ Switch.vue sets `inheritAttrs: false` and binds `$attrs` on its sr-only
38
+ input, so a class on <Switch> never reaches its root <label>. The child
39
+ variant below styles that label from the header instead, which keeps the
40
+ whole row clickable and the accessible name on the real <label>. The gap
41
+ has to go on that label too: the header has a single child in both modes,
42
+ so its own `gap` would never apply and the spacing would silently fall
43
+ back to the `gap-2` that Switch.vue sets for itself.
44
+ -->
45
+ <div class="flex items-center [&>label]:flex [&>label]:w-full [&>label]:gap-3">
46
+ <Switch v-if="switchable" v-model="model" size="sm" color="blue" label-position="before">
47
+ <span class="grow text-left small-normal text-gray-900">{{ label }}</span>
48
+ </Switch>
49
+ <p v-else class="small-normal text-gray-900">{{ label }}</p>
50
+ </div>
51
+
52
+ <div
53
+ v-if="$slots.default"
54
+ :inert="inert"
55
+ :class="[
56
+ 'grid',
57
+ open ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]',
58
+ switchable &&
59
+ 'transition-[grid-template-rows] duration-300 ease-in-out motion-reduce:transition-none',
60
+ ]"
61
+ >
62
+ <!--
63
+ `overflow-hidden` is what makes the 0fr collapse clip, but it also clips
64
+ a focus ring on a full-width control in the slot, and the block has no
65
+ horizontal padding of its own. `-mx-1` widens the clipping box by 4px on
66
+ each side and the `px-1` below pushes the content back, so the ring has
67
+ room while the content keeps the same x position as the label.
68
+ -->
69
+ <div
70
+ :class="[
71
+ '-mx-1 min-h-0 overflow-hidden',
72
+ open ? 'opacity-100' : 'opacity-0',
73
+ switchable && 'transition-opacity duration-200 ease-in-out motion-reduce:transition-none',
74
+ ]"
75
+ >
76
+ <!-- Padding sits on the inner element so nothing is left over at 0fr. -->
77
+ <div class="px-1 pt-3 pb-1">
78
+ <slot />
79
+ </div>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </template>
@@ -60,5 +60,6 @@
60
60
  "NexxtTimelinePhaseblock": "components/organisms/TimelinePhaseblock/TimelinePhaseblock.vue",
61
61
  "NexxtTimelineTrack": "components/organisms/TimelineTrack/TimelineTrack.vue",
62
62
  "NexxtToaster": "components/organisms/Toaster/Toaster.vue",
63
- "NexxtVideoPlayer": "components/organisms/VideoPlayer/VideoPlayer.vue"
63
+ "NexxtVideoPlayer": "components/organisms/VideoPlayer/VideoPlayer.vue",
64
+ "NexxtEditorSettingsBlock": "components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue"
64
65
  }
package/src/index.ts CHANGED
@@ -36,6 +36,7 @@ export { default as NexxtCustomerJourneyTile } from './components/molecules/Cust
36
36
  export { default as NexxtDatePicker } from './components/organisms/DatePicker/DatePicker.vue'
37
37
  export { default as NexxtDoughnutChart } from './components/molecules/DoughnutChart/DoughnutChart.vue'
38
38
  export { default as NexxtDropdownButton } from './components/organisms/DropdownButton/DropdownButton.vue'
39
+ export { default as NexxtEditorSettingsBlock } from './components/editor/atoms/EditorSettingsBlock/EditorSettingsBlock.vue'
39
40
  export { default as NexxtEnergyLabel } from './components/atoms/EnergyLabel/EnergyLabel.vue'
40
41
  export { default as NexxtFloatingPanel } from './components/atoms/FloatingPanel/FloatingPanel.vue'
41
42
  export { default as NexxtHeader } from './components/organisms/Header/Header.vue'
package/src/nuxt.ts CHANGED
@@ -92,8 +92,21 @@ const module: NuxtModule<ModuleOptions> = defineNuxtModule<ModuleOptions>({
92
92
  .replace(/\/+/g, '/')
93
93
  .replace(/^\/|\/$/g, '')}/`
94
94
 
95
- nuxt.options.nitro.publicAssets ??= []
96
- nuxt.options.nitro.publicAssets.push({
95
+ // @nuxt/schema 4.x no longer declares `nitro` on NuxtOptions; the typing
96
+ // arrives through module augmentation in @nuxt/nitro-server, which ships
97
+ // with `nuxt` itself. This package depends on @nuxt/kit and @nuxt/schema
98
+ // only — deliberately, to stay free of app coupling — so the augmentation
99
+ // is absent here and the property has to be described locally. At runtime
100
+ // in a consumer the object is always present. Intersecting rather than
101
+ // replacing keeps this compatible with an installation that does have the
102
+ // augmentation: `options` stays the same object, so the mutation below
103
+ // still targets `nuxt.options.nitro`.
104
+ const options = nuxt.options as typeof nuxt.options & {
105
+ nitro: { publicAssets?: { dir: string; baseURL?: string; maxAge?: number }[] }
106
+ }
107
+
108
+ options.nitro.publicAssets ??= []
109
+ options.nitro.publicAssets.push({
97
110
  dir: assetsDir,
98
111
  baseURL,
99
112
  // Content-hashed filenames, so they are safe to cache indefinitely.