@tekkare/romulus 0.1.204 → 0.1.206

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.203",
7
+ "version": "0.1.205",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -51,6 +51,8 @@ const module = defineNuxtModule({
51
51
  if (!nuxt.options.app.head.link.some((l) => l.href === phosphorFillHref)) {
52
52
  nuxt.options.app.head.link.push({ rel: "stylesheet", href: phosphorFillHref });
53
53
  }
54
+ const optimizeDeps = nuxt.options.vite.optimizeDeps ||= {};
55
+ optimizeDeps.include = [...optimizeDeps.include || [], "@phosphor-icons/vue"];
54
56
  }
55
57
  });
56
58
 
@@ -76,9 +76,16 @@ export interface RmHeaderTab {
76
76
  hint?: string
77
77
  /**
78
78
  * Onglet present mais sans objet : grise, il ne se selectionne pas. Lu par
79
- * RmRailPanel, ou un groupe de panneaux garde tous ses onglets en place.
79
+ * RmRailPanel, ou un groupe de panneaux garde tous ses onglets en place, et
80
+ * par RmPageHeader, pour une section annoncee mais pas encore ouverte.
80
81
  */
81
82
  disabled?: boolean
83
+ /**
84
+ * Mention courte posee apres le libelle (« Coming soon », « Beta ») : ce
85
+ * que l'onglet est, la ou `count` dit combien il contient. Lu par
86
+ * RmPageHeader.
87
+ */
88
+ tag?: string
82
89
  }
83
90
 
84
91
  withDefaults(defineProps<{
@@ -9,44 +9,36 @@
9
9
  icone deja chargee : une liste de trois cents lignes posait trois cents
10
10
  attentes, et les icones apparaissaient apres le texte.
11
11
  -->
12
- <script setup lang="ts">
13
- import { computed, defineAsyncComponent, shallowRef, type Component } from 'vue'
14
-
15
- export interface RmIconProps {
16
- /** Nom Phosphor sans le prefixe « Ph » (« House », « Gear », « ChartBar »). */
17
- name: string
18
- /** Taille en pixels. */
19
- size?: number
20
- /** Graisse du trait. `fill` donne la forme pleine. */
21
- weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
22
- color?: string
23
- }
24
-
25
- const props = withDefaults(defineProps<RmIconProps>(), {
26
- size: 20,
27
- weight: 'regular',
28
- color: undefined,
29
- })
12
+ <script lang="ts">
13
+ import { defineAsyncComponent, type Component } from 'vue'
30
14
 
31
15
  /**
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.
16
+ * Etat partage par toutes les instances : il vit dans le module, pas dans
17
+ * `<script setup>` (qui le recreait a chaque instance, donc une attente par
18
+ * icone).
35
19
  */
36
20
  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>>>()
21
+ let iconModule: Promise<Record<string, Component>> | undefined
22
+ /** Le paquet une fois charge : les icones se posent alors sans attente. */
23
+ let loaded: Record<string, Component> | undefined
40
24
 
41
25
  function loadIcons() {
42
- if (!iconModule.value) {
43
- iconModule.value = import('@phosphor-icons/vue') as unknown as Promise<Record<string, Component>>
26
+ if (!iconModule) {
27
+ iconModule = (import('@phosphor-icons/vue') as unknown as Promise<Record<string, Component>>)
28
+ .then((mod) => {
29
+ loaded = mod
30
+ return mod
31
+ })
44
32
  }
45
- return iconModule.value
33
+ return iconModule
46
34
  }
47
35
 
36
+ // Le paquet est demande des l'import du composant, pas au premier montage.
37
+ if (typeof window !== 'undefined') loadIcons()
38
+
48
39
  function resolve(name: string) {
49
40
  const key = `Ph${name}`
41
+ if (loaded) return loaded[key] || loaded.PhQuestion
50
42
  let component = cache.get(key)
51
43
  if (!component) {
52
44
  component = defineAsyncComponent(() =>
@@ -56,6 +48,26 @@ function resolve(name: string) {
56
48
  }
57
49
  return component
58
50
  }
51
+ </script>
52
+
53
+ <script setup lang="ts">
54
+ import { computed } from 'vue'
55
+
56
+ export interface RmIconProps {
57
+ /** Nom Phosphor sans le prefixe « Ph » (« House », « Gear », « ChartBar »). */
58
+ name: string
59
+ /** Taille en pixels. */
60
+ size?: number
61
+ /** Graisse du trait. `fill` donne la forme pleine. */
62
+ weight?: 'thin' | 'light' | 'regular' | 'bold' | 'fill' | 'duotone'
63
+ color?: string
64
+ }
65
+
66
+ const props = withDefaults(defineProps<RmIconProps>(), {
67
+ size: 20,
68
+ weight: 'regular',
69
+ color: undefined,
70
+ })
59
71
 
60
72
  const iconComponent = computed(() => resolve(props.name))
61
73
  </script>
@@ -81,22 +81,24 @@ const router = useRouter()
81
81
  v-for="tab in tabs"
82
82
  :key="tab.key"
83
83
  class="rm-page-header__tab"
84
- :class="{ 'rm-page-header__tab--active': tab.active }"
84
+ :class="{ 'rm-page-header__tab--active': tab.active, 'rm-page-header__tab--disabled': tab.disabled }"
85
85
  type="button"
86
86
  role="tab"
87
87
  :aria-selected="tab.active ? 'true' : 'false'"
88
+ :aria-disabled="tab.disabled || undefined"
88
89
  :title="tab.hint || undefined"
89
- @click="emit('tab', tab.key)"
90
+ @click="!tab.disabled && emit('tab', tab.key)"
90
91
  >
91
92
  {{ tab.label }}
92
93
  <span v-if="tab.count !== undefined && tab.count !== null" class="rm-page-header__tab-count">
93
94
  {{ tab.count }}
94
95
  </span>
96
+ <span v-if="tab.tag" class="rm-page-header__tab-tag">{{ tab.tag }}</span>
95
97
  </button>
96
98
  </div>
97
99
  </header>
98
100
  </template>
99
101
 
100
102
  <style scoped>
101
- .rm-page-header{backdrop-filter:blur(12px);background:color-mix(in srgb,var(--bg-surface-3) 80%,transparent);border-bottom:1px solid var(--border-default);box-sizing:border-box;color:var(--text-primary);display:flex;flex-direction:column;font-family:var(--font-sans);gap:var(--space-12);padding:var(--space-16) var(--space-32) var(--space-12);position:sticky;top:0;width:100%;z-index:95}.rm-page-header__row{align-items:center;align-self:stretch;display:flex;gap:var(--space-16)}.rm-page-header__back{background:transparent;border:none;color:inherit;cursor:pointer;display:inline-flex;padding:0}.rm-page-header__heading{flex-grow:2;min-width:0}.rm-page-header__eyebrow{color:var(--text-muted);font-size:var(--font-12);font-weight:var(--weight-medium);margin:0 0 2px}.rm-page-header__title{flex-grow:2;font-family:var(--font-serif);font-size:var(--font-32);font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0;min-width:0}.rm-page-header__title :deep(h1),.rm-page-header__title :deep(h2),.rm-page-header__title :deep(p){font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;margin:0}.rm-page-header__actions{align-items:center;display:flex;flex:0 0 auto;gap:var(--space-16)}.rm-page-header__tabs{display:flex;gap:var(--space-8);margin-bottom:-13px;overflow-x:auto}.rm-page-header__tab{background:none;border:none;border-bottom:3px solid transparent;border-radius:8px 8px 0 0;color:var(--text-muted);cursor:pointer;font-family:inherit;font-size:var(--font-14);font-weight:500;line-height:1.6;padding:var(--space-8) var(--space-16) var(--space-10);transition:background-color .3s,color .15s;white-space:nowrap}.rm-page-header__tab:hover{color:var(--color-primary)}.rm-page-header__tab-count{background:color-mix(in srgb,currentColor 12%,transparent);border-radius:var(--radius-pill);display:inline-block;font-size:var(--font-12);font-weight:600;line-height:1.5;margin-left:var(--space-6);padding:0 var(--space-6)}.rm-page-header__tab--active{background:color-mix(in srgb,var(--color-primary) 6%,transparent);border-bottom-color:var(--color-primary);color:var(--color-primary);font-weight:600}
103
+ .rm-page-header{backdrop-filter:blur(12px);background:color-mix(in srgb,var(--bg-surface-3) 80%,transparent);border-bottom:1px solid var(--border-default);box-sizing:border-box;color:var(--text-primary);display:flex;flex-direction:column;font-family:var(--font-sans);gap:var(--space-12);padding:var(--space-16) var(--space-32) var(--space-12);position:sticky;top:0;width:100%;z-index:95}.rm-page-header__row{align-items:center;align-self:stretch;display:flex;gap:var(--space-16)}.rm-page-header__back{background:transparent;border:none;color:inherit;cursor:pointer;display:inline-flex;padding:0}.rm-page-header__heading{flex-grow:2;min-width:0}.rm-page-header__eyebrow{color:var(--text-muted);font-size:var(--font-12);font-weight:var(--weight-medium);margin:0 0 2px}.rm-page-header__title{flex-grow:2;font-family:var(--font-serif);font-size:var(--font-32);font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0;min-width:0}.rm-page-header__title :deep(h1),.rm-page-header__title :deep(h2),.rm-page-header__title :deep(p){font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;margin:0}.rm-page-header__actions{align-items:center;display:flex;flex:0 0 auto;gap:var(--space-16)}.rm-page-header__tabs{display:flex;gap:var(--space-8);margin-bottom:-13px;overflow-x:auto}.rm-page-header__tab{background:none;border:none;border-bottom:3px solid transparent;border-radius:8px 8px 0 0;color:var(--text-muted);cursor:pointer;font-family:inherit;font-size:var(--font-14);font-weight:500;line-height:1.6;padding:var(--space-8) var(--space-16) var(--space-10);transition:background-color .3s,color .15s;white-space:nowrap}.rm-page-header__tab:hover{color:var(--color-primary)}.rm-page-header__tab-count{background:color-mix(in srgb,currentColor 12%,transparent);border-radius:var(--radius-pill);font-size:var(--font-12)}.rm-page-header__tab-count,.rm-page-header__tab-tag{display:inline-block;font-weight:600;line-height:1.5;margin-left:var(--space-6);padding:0 var(--space-6)}.rm-page-header__tab-tag{border:1px solid;border-radius:var(--radius-pill);font-size:var(--font-11,11px);letter-spacing:.02em;vertical-align:1px}.rm-page-header__tab--disabled{cursor:not-allowed;opacity:.6}.rm-page-header__tab--disabled,.rm-page-header__tab--disabled:hover{color:var(--text-disabled,var(--text-muted))}.rm-page-header__tab--active{background:color-mix(in srgb,var(--color-primary) 6%,transparent);border-bottom-color:var(--color-primary);color:var(--color-primary);font-weight:600}
102
104
  </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekkare/romulus",
3
- "version": "0.1.204",
3
+ "version": "0.1.206",
4
4
  "description": "Romulus Design System - Nuxt module by Tekkare",
5
5
  "license": "MIT",
6
6
  "type": "module",