@tekkare/romulus 0.1.78 → 0.1.79

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/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.16.0"
6
6
  },
7
- "version": "0.1.77",
7
+ "version": "0.1.78",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
@@ -27,6 +27,7 @@
27
27
  -->
28
28
  <script setup lang="ts">
29
29
  import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
30
+ import { PhCaretDown, PhInfo, PhMagnifyingGlass, PhMinusCircle, PhPlusCircle } from '@phosphor-icons/vue'
30
31
  import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
31
32
 
32
33
  export interface RmComplexSelectPreset {
@@ -254,7 +255,7 @@ onUnmounted(() => {
254
255
  <p class="rm-csel__label">
255
256
  {{ label }}
256
257
  <button v-if="labelInfo" type="button" class="rm-csel__info" @click="emit('openInfo')">
257
- <RmIcon name="Info" :size="14" />
258
+ <PhInfo :size="14" />
258
259
  </button>
259
260
  </p>
260
261
 
@@ -275,7 +276,7 @@ onUnmounted(() => {
275
276
  <span v-if="showAmount && selected.length > 0" class="rm-csel__count">
276
277
  {{ selected.length > 99 ? '99+' : selected.length }}
277
278
  </span>
278
- <RmIcon name="CaretDown" :size="16" />
279
+ <PhCaretDown :size="16" />
279
280
  </button>
280
281
 
281
282
  <div
@@ -316,7 +317,7 @@ onUnmounted(() => {
316
317
  </div>
317
318
 
318
319
  <div class="rm-csel__search">
319
- <RmIcon name="MagnifyingGlass" :size="14" />
320
+ <PhMagnifyingGlass :size="14" />
320
321
  <input
321
322
  ref="addRef"
322
323
  v-model="addSearch"
@@ -342,7 +343,7 @@ onUnmounted(() => {
342
343
  class="rm-csel__option rm-csel__option--add"
343
344
  @click="add(option)"
344
345
  >
345
- <RmIcon name="PlusCircle" :size="16" weight="fill" />
346
+ <PhPlusCircle :size="16" weight="fill" />
346
347
  <span>{{ option }}</span>
347
348
  </button>
348
349
  </div>
@@ -362,7 +363,7 @@ onUnmounted(() => {
362
363
  </div>
363
364
 
364
365
  <div class="rm-csel__search">
365
- <RmIcon name="MagnifyingGlass" :size="14" />
366
+ <PhMagnifyingGlass :size="14" />
366
367
  <input
367
368
  v-model="removeSearch"
368
369
  type="search"
@@ -384,7 +385,7 @@ onUnmounted(() => {
384
385
  class="rm-csel__option rm-csel__option--remove"
385
386
  @click="remove(option)"
386
387
  >
387
- <RmIcon name="MinusCircle" :size="16" weight="fill" />
388
+ <PhMinusCircle :size="16" weight="fill" />
388
389
  <span>{{ option }}</span>
389
390
  </button>
390
391
  </div>
@@ -27,6 +27,7 @@
27
27
  -->
28
28
  <script setup lang="ts">
29
29
  import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
30
+ import { PhCaretDown, PhCaretUpDown, PhCheckCircle, PhCircle, PhMagnifyingGlass } from '@phosphor-icons/vue'
30
31
  import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
31
32
 
32
33
  const props = withDefaults(defineProps<{
@@ -187,12 +188,12 @@ onUnmounted(() => {
187
188
  {{ selected || emptyLabel || t.empty }}
188
189
  </span>
189
190
  </RmTooltip>
190
- <RmIcon :name="sortIcon ? 'CaretUpDown' : 'CaretDown'" :size="16" />
191
+ <component :is="sortIcon ? PhCaretUpDown : PhCaretDown" :size="16" />
191
192
  </button>
192
193
 
193
194
  <div v-show="isOpen" class="rm-dsel__panel" @click.stop>
194
195
  <div v-if="search" class="rm-dsel__search">
195
- <RmIcon name="MagnifyingGlass" :size="16" />
196
+ <PhMagnifyingGlass :size="16" />
196
197
  <input
197
198
  ref="searchRef"
198
199
  v-model="searchTerm"
@@ -222,8 +223,8 @@ onUnmounted(() => {
222
223
  @click="pick(option)"
223
224
  @mousemove="activeIndex = index"
224
225
  >
225
- <RmIcon
226
- :name="option === selected ? 'CheckCircle' : 'Circle'"
226
+ <component
227
+ :is="option === selected ? PhCheckCircle : PhCircle"
227
228
  :size="16"
228
229
  :weight="option === selected ? 'fill' : 'regular'"
229
230
  />
@@ -1,14 +1,24 @@
1
+ <!--
2
+ RmIcon - une icone Phosphor designee par son nom.
3
+
4
+ Le composant charge le paquet d'icones a la demande : l'embarquer en entier
5
+ dans le premier rendu pesait plus lourd que tout le reste du panneau.
6
+
7
+ Les composants resolus sont gardes dans un cache commun a la page. Sans lui,
8
+ chaque instance fabriquait son propre composant asynchrone, meme pour une
9
+ icone deja chargee : une liste de trois cents lignes posait trois cents
10
+ attentes, et les icones apparaissaient apres le texte.
11
+ -->
1
12
  <script setup lang="ts">
2
- import { computed, defineAsyncComponent, type Component } from 'vue'
13
+ import { computed, defineAsyncComponent, shallowRef, type Component } from 'vue'
3
14
 
4
15
  export interface RmIconProps {
5
- /** Phosphor icon name without the "Ph" prefix (e.g. "House", "Gear", "ChartBar") */
16
+ /** Nom Phosphor sans le prefixe « Ph » (« House », « Gear », « ChartBar »). */
6
17
  name: string
7
- /** Icon size in pixels */
18
+ /** Taille en pixels. */
8
19
  size?: number
9
- /** Icon weight: thin, light, regular, bold, fill, duotone */
20
+ /** Graisse du trait. `fill` donne la forme pleine. */
10
21
  weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
11
- /** Icon color */
12
22
  color?: string
13
23
  }
14
24
 
@@ -18,14 +28,36 @@ const props = withDefaults(defineProps<RmIconProps>(), {
18
28
  color: undefined,
19
29
  })
20
30
 
21
- const iconComponent = computed<Component>(() => {
22
- const iconName = `Ph${props.name}`
23
- return defineAsyncComponent(() =>
24
- import('@phosphor-icons/vue').then((mod) => {
25
- return (mod as Record<string, Component>)[iconName] || mod.PhQuestion
26
- }),
27
- )
28
- })
31
+ /**
32
+ * Un composant asynchrone par nom d'icone, partage par toutes les instances.
33
+ * Une fois le paquet charge, le composant garde sa resolution et se pose sans
34
+ * attente au montage suivant.
35
+ */
36
+ const cache = new Map<string, Component>()
37
+
38
+ /** Le module, demande une seule fois quel que soit le nombre d'icones. */
39
+ const iconModule = shallowRef<Promise<Record<string, Component>>>()
40
+
41
+ function loadIcons() {
42
+ if (!iconModule.value) {
43
+ iconModule.value = import('@phosphor-icons/vue') as unknown as Promise<Record<string, Component>>
44
+ }
45
+ return iconModule.value
46
+ }
47
+
48
+ function resolve(name: string) {
49
+ const key = `Ph${name}`
50
+ let component = cache.get(key)
51
+ if (!component) {
52
+ component = defineAsyncComponent(() =>
53
+ loadIcons().then(mod => mod[key] || mod.PhQuestion),
54
+ )
55
+ cache.set(key, component)
56
+ }
57
+ return component
58
+ }
59
+
60
+ const iconComponent = computed(() => resolve(props.name))
29
61
  </script>
30
62
 
31
63
  <template>
@@ -36,6 +68,8 @@ const iconComponent = computed<Component>(() => {
36
68
  :weight="weight"
37
69
  :color="color"
38
70
  />
71
+ <!-- La place est reservee des le premier rendu : sans elle, le texte se
72
+ decale lateralement quand l'icone arrive. -->
39
73
  <template #fallback>
40
74
  <span :style="{ display: 'inline-block', width: size + 'px', height: size + 'px' }" />
41
75
  </template>
@@ -25,6 +25,7 @@
25
25
  -->
26
26
  <script setup lang="ts">
27
27
  import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
28
+ import { PhCaretDown, PhCheckSquare, PhInfo, PhMagnifyingGlass, PhSquare } from '@phosphor-icons/vue'
28
29
  import { rmPanelOpened, rmPanelRegister } from '../utils/panels'
29
30
 
30
31
  const props = withDefaults(defineProps<{
@@ -175,7 +176,7 @@ onUnmounted(() => {
175
176
  <p class="rm-msel__label">
176
177
  {{ label }}
177
178
  <button v-if="labelInfo" type="button" class="rm-msel__info" @click="emit('openInfo')">
178
- <RmIcon name="Info" :size="14" />
179
+ <PhInfo :size="14" />
179
180
  </button>
180
181
  </p>
181
182
 
@@ -196,12 +197,12 @@ onUnmounted(() => {
196
197
  <span v-if="showAmount && selected.length > 0" class="rm-msel__count">
197
198
  {{ selected.length > 99 ? '99+' : selected.length }}
198
199
  </span>
199
- <RmIcon name="CaretDown" :size="16" />
200
+ <PhCaretDown :size="16" />
200
201
  </button>
201
202
 
202
203
  <div v-show="isOpen" class="rm-msel__panel" @click.stop>
203
204
  <div v-if="search" class="rm-msel__search">
204
- <RmIcon name="MagnifyingGlass" :size="16" />
205
+ <PhMagnifyingGlass :size="16" />
205
206
  <input
206
207
  ref="searchRef"
207
208
  v-model="searchTerm"
@@ -230,8 +231,8 @@ onUnmounted(() => {
230
231
  :aria-checked="allSelected"
231
232
  @click="toggleAll"
232
233
  >
233
- <RmIcon
234
- :name="allSelected ? 'CheckSquare' : 'Square'"
234
+ <component
235
+ :is="allSelected ? PhCheckSquare : PhSquare"
235
236
  :size="16"
236
237
  :weight="allSelected ? 'fill' : 'regular'"
237
238
  />
@@ -249,8 +250,8 @@ onUnmounted(() => {
249
250
  :aria-checked="selected.includes(option)"
250
251
  @click="toggleOption(option)"
251
252
  >
252
- <RmIcon
253
- :name="selected.includes(option) ? 'CheckSquare' : 'Square'"
253
+ <component
254
+ :is="selected.includes(option) ? PhCheckSquare : PhSquare"
254
255
  :size="16"
255
256
  :weight="selected.includes(option) ? 'fill' : 'regular'"
256
257
  />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekkare/romulus",
3
- "version": "0.1.78",
3
+ "version": "0.1.79",
4
4
  "description": "Romulus Design System - Nuxt module by Tekkare",
5
5
  "license": "MIT",
6
6
  "type": "module",