@softdin/shared 0.1.3 → 0.3.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,6 +1,6 @@
1
1
  {
2
2
  "name": "@softdin/shared",
3
- "version": "0.1.3",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "src",
@@ -41,10 +41,23 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "axios": "^1.18.1",
44
- "softdinlibreriajs": "^12.0.43"
44
+ "softdinlibreriajs": "^15.0.0"
45
45
  },
46
46
  "repository": {
47
47
  "type": "git",
48
- "url": "https://github.com/DinSoftdin/softdin-shared.git"
48
+ "url": "git+https://github.com/DinSoftdin/softdin-shared.git"
49
+ },
50
+ "peerDependencies": {
51
+ "vue": "^3.5.0"
52
+ },
53
+ "devDependencies": {
54
+ "@vue/tsconfig": "^0.9.1",
55
+ "typescript": "~6.0.2",
56
+ "vite": "^7.1.7",
57
+ "vue": "^3.5.34",
58
+ "vue-tsc": "^3.2.8"
59
+ },
60
+ "scripts": {
61
+ "typecheck": "vue-tsc --noEmit"
49
62
  }
50
63
  }
@@ -1,143 +1,143 @@
1
- <script setup lang="ts">
2
- withDefaults(
3
- defineProps<{
4
- maximized?: boolean
5
- disabled?: boolean
6
- maximizeLabel?: string
7
- restoreLabel?: string
8
- }>(),
9
- {
10
- maximized: false,
11
- disabled: false,
12
- maximizeLabel: 'Maximizar',
13
- restoreLabel: 'Restaurar',
14
- },
15
- )
16
-
17
- defineEmits<{
18
- click: [event: MouseEvent]
19
- }>()
20
- </script>
21
-
22
- <template>
23
- <button
24
- type="button"
25
- class="softdin-form-maximize"
26
- :aria-label="maximized ? restoreLabel : maximizeLabel"
27
- :title="maximized ? restoreLabel : maximizeLabel"
28
- :aria-pressed="maximized"
29
- :disabled="disabled"
30
- @click="$emit('click', $event)"
31
- >
32
- <!-- Restaurar: flechas hacia adentro (como en Perfil de Cargo) -->
33
- <svg
34
- v-if="maximized"
35
- class="softdin-form-maximize__icon"
36
- viewBox="0 0 20 20"
37
- aria-hidden="true"
38
- >
39
- <path d="M7.5 3.5v4h-4" />
40
- <path d="M12.5 3.5v4h4" />
41
- <path d="M7.5 16.5v-4h-4" />
42
- <path d="M12.5 16.5v-4h4" />
43
- <path d="M7.5 7.5 3.5 3.5" />
44
- <path d="M12.5 7.5l4-4" />
45
- <path d="M7.5 12.5l-4 4" />
46
- <path d="M12.5 12.5l4 4" />
47
- </svg>
48
- <!-- Maximizar: flechas hacia las esquinas -->
49
- <svg v-else class="softdin-form-maximize__icon" viewBox="0 0 20 20" aria-hidden="true">
50
- <path d="M3.5 7.5v-4h4" />
51
- <path d="M16.5 7.5v-4h-4" />
52
- <path d="M3.5 12.5v4h4" />
53
- <path d="M16.5 12.5v4h-4" />
54
- <path d="M3.5 3.5 7.5 7.5" />
55
- <path d="M16.5 3.5 12.5 7.5" />
56
- <path d="M3.5 16.5 7.5 12.5" />
57
- <path d="M16.5 16.5 12.5 12.5" />
58
- </svg>
59
- <span>{{ maximized ? restoreLabel : maximizeLabel }}</span>
60
- </button>
61
- </template>
62
-
63
- <style scoped>
64
- .softdin-form-maximize {
65
- position: relative;
66
- display: inline-flex;
67
- align-items: center;
68
- justify-content: center;
69
- width: 2.25rem;
70
- height: 2.25rem;
71
- border: 1px solid #cbd5e1;
72
- border-radius: 9999px;
73
- background: #f8fafc;
74
- padding: 0;
75
- color: #475569;
76
- cursor: pointer;
77
- transition: transform 180ms ease, box-shadow 180ms ease, background 180ms ease, color 180ms ease;
78
- }
79
-
80
- .softdin-form-maximize:hover:not(:disabled),
81
- .softdin-form-maximize:focus-visible {
82
- background: #f1f5f9;
83
- color: #0f172a;
84
- box-shadow: 0 6px 14px rgba(15, 23, 42, 0.12);
85
- transform: translateY(-2px) rotate(4deg);
86
- }
87
-
88
- .softdin-form-maximize:focus-visible {
89
- outline: 2px solid #64748b;
90
- outline-offset: 2px;
91
- }
92
-
93
- .softdin-form-maximize:disabled {
94
- opacity: 0.55;
95
- cursor: not-allowed;
96
- }
97
-
98
- .softdin-form-maximize span {
99
- position: absolute;
100
- top: 50%;
101
- right: calc(100% + 0.5rem);
102
- z-index: 2;
103
- transform: translateY(-50%) translateX(0.25rem);
104
- border-radius: 0.375rem;
105
- background: #0f172a;
106
- padding: 0.25rem 0.5rem;
107
- font-size: 0.75rem;
108
- font-weight: 600;
109
- white-space: nowrap;
110
- color: #fff;
111
- opacity: 0;
112
- pointer-events: none;
113
- transition: opacity 150ms ease, transform 150ms ease;
114
- }
115
-
116
- .softdin-form-maximize:hover:not(:disabled) span,
117
- .softdin-form-maximize:focus-visible span {
118
- transform: translateY(-50%) translateX(0) rotate(-4deg);
119
- opacity: 1;
120
- }
121
-
122
- .softdin-form-maximize__icon {
123
- width: 1rem;
124
- height: 1rem;
125
- fill: none;
126
- stroke: currentColor;
127
- stroke-width: 1.8;
128
- stroke-linecap: round;
129
- stroke-linejoin: round;
130
- }
131
-
132
- @media (prefers-reduced-motion: reduce) {
133
- .softdin-form-maximize,
134
- .softdin-form-maximize span {
135
- transition: none;
136
- }
137
-
138
- .softdin-form-maximize:hover:not(:disabled),
139
- .softdin-form-maximize:focus-visible {
140
- transform: none;
141
- }
142
- }
143
- </style>
1
+ <script setup lang="ts">
2
+ withDefaults(
3
+ defineProps<{
4
+ maximized?: boolean
5
+ disabled?: boolean
6
+ maximizeLabel?: string
7
+ restoreLabel?: string
8
+ }>(),
9
+ {
10
+ maximized: false,
11
+ disabled: false,
12
+ maximizeLabel: 'Maximizar',
13
+ restoreLabel: 'Restaurar',
14
+ },
15
+ )
16
+
17
+ defineEmits<{
18
+ click: [event: MouseEvent]
19
+ }>()
20
+ </script>
21
+
22
+ <template>
23
+ <button
24
+ type="button"
25
+ class="softdin-form-maximize"
26
+ :aria-label="maximized ? restoreLabel : maximizeLabel"
27
+ :title="maximized ? restoreLabel : maximizeLabel"
28
+ :aria-pressed="maximized"
29
+ :disabled="disabled"
30
+ @click="$emit('click', $event)"
31
+ >
32
+ <!-- Restaurar: flechas hacia adentro (como en Perfil de Cargo) -->
33
+ <svg
34
+ v-if="maximized"
35
+ class="softdin-form-maximize__icon"
36
+ viewBox="0 0 20 20"
37
+ aria-hidden="true"
38
+ >
39
+ <path d="M7.5 3.5v4h-4" />
40
+ <path d="M12.5 3.5v4h4" />
41
+ <path d="M7.5 16.5v-4h-4" />
42
+ <path d="M12.5 16.5v-4h4" />
43
+ <path d="M7.5 7.5 3.5 3.5" />
44
+ <path d="M12.5 7.5l4-4" />
45
+ <path d="M7.5 12.5l-4 4" />
46
+ <path d="M12.5 12.5l4 4" />
47
+ </svg>
48
+ <!-- Maximizar: flechas hacia las esquinas -->
49
+ <svg v-else class="softdin-form-maximize__icon" viewBox="0 0 20 20" aria-hidden="true">
50
+ <path d="M3.5 7.5v-4h4" />
51
+ <path d="M16.5 7.5v-4h-4" />
52
+ <path d="M3.5 12.5v4h4" />
53
+ <path d="M16.5 12.5v4h-4" />
54
+ <path d="M3.5 3.5 7.5 7.5" />
55
+ <path d="M16.5 3.5 12.5 7.5" />
56
+ <path d="M3.5 16.5 7.5 12.5" />
57
+ <path d="M16.5 16.5 12.5 12.5" />
58
+ </svg>
59
+ <span>{{ maximized ? restoreLabel : maximizeLabel }}</span>
60
+ </button>
61
+ </template>
62
+
63
+ <style scoped>
64
+ .softdin-form-maximize {
65
+ position: relative;
66
+ display: inline-flex;
67
+ align-items: center;
68
+ justify-content: center;
69
+ width: 2.25rem;
70
+ height: 2.25rem;
71
+ border: 1px solid #cbd5e1;
72
+ border-radius: 9999px;
73
+ background: #f8fafc;
74
+ padding: 0;
75
+ color: #475569;
76
+ cursor: pointer;
77
+ transition: transform 180ms ease, box-shadow 180ms ease, background 180ms ease, color 180ms ease;
78
+ }
79
+
80
+ .softdin-form-maximize:hover:not(:disabled),
81
+ .softdin-form-maximize:focus-visible {
82
+ background: #f1f5f9;
83
+ color: #0f172a;
84
+ box-shadow: 0 6px 14px rgba(15, 23, 42, 0.12);
85
+ transform: translateY(-2px) rotate(4deg);
86
+ }
87
+
88
+ .softdin-form-maximize:focus-visible {
89
+ outline: 2px solid #64748b;
90
+ outline-offset: 2px;
91
+ }
92
+
93
+ .softdin-form-maximize:disabled {
94
+ opacity: 0.55;
95
+ cursor: not-allowed;
96
+ }
97
+
98
+ .softdin-form-maximize span {
99
+ position: absolute;
100
+ top: 50%;
101
+ right: calc(100% + 0.5rem);
102
+ z-index: 2;
103
+ transform: translateY(-50%) translateX(0.25rem);
104
+ border-radius: 0.375rem;
105
+ background: #0f172a;
106
+ padding: 0.25rem 0.5rem;
107
+ font-size: 0.75rem;
108
+ font-weight: 600;
109
+ white-space: nowrap;
110
+ color: #fff;
111
+ opacity: 0;
112
+ pointer-events: none;
113
+ transition: opacity 150ms ease, transform 150ms ease;
114
+ }
115
+
116
+ .softdin-form-maximize:hover:not(:disabled) span,
117
+ .softdin-form-maximize:focus-visible span {
118
+ transform: translateY(-50%) translateX(0) rotate(-4deg);
119
+ opacity: 1;
120
+ }
121
+
122
+ .softdin-form-maximize__icon {
123
+ width: 1rem;
124
+ height: 1rem;
125
+ fill: none;
126
+ stroke: currentColor;
127
+ stroke-width: 1.8;
128
+ stroke-linecap: round;
129
+ stroke-linejoin: round;
130
+ }
131
+
132
+ @media (prefers-reduced-motion: reduce) {
133
+ .softdin-form-maximize,
134
+ .softdin-form-maximize span {
135
+ transition: none;
136
+ }
137
+
138
+ .softdin-form-maximize:hover:not(:disabled),
139
+ .softdin-form-maximize:focus-visible {
140
+ transform: none;
141
+ }
142
+ }
143
+ </style>
@@ -1,113 +1,113 @@
1
- <script setup lang="ts">
2
- withDefaults(defineProps<{
3
- currentPage: number
4
- lastPage: number
5
- disabled?: boolean
6
- }>(), {
7
- disabled: false,
8
- })
9
-
10
- const emit = defineEmits<{
11
- go: [page: number]
12
- }>()
13
- </script>
14
-
15
- <template>
16
- <footer v-if="lastPage > 1" class="pagination">
17
- <button
18
- type="button"
19
- class="page-btn"
20
- :disabled="disabled || currentPage <= 1"
21
- title="Inicio"
22
- aria-label="Inicio"
23
- @click="emit('go', 1)"
24
- >
25
- <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
26
- <path fill="currentColor" d="M18.41 16.59 13.82 12l4.59-4.59L17 6l-6 6 6 6zM6 6h2v12H6z" />
27
- </svg>
28
- </button>
29
- <button
30
- type="button"
31
- class="page-btn"
32
- :disabled="disabled || currentPage <= 1"
33
- title="Anterior"
34
- aria-label="Anterior"
35
- @click="emit('go', currentPage - 1)"
36
- >
37
- <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
38
- <path fill="currentColor" d="M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
39
- </svg>
40
- </button>
41
- <span class="pagination-label">Página {{ currentPage }} de {{ lastPage }}</span>
42
- <button
43
- type="button"
44
- class="page-btn"
45
- :disabled="disabled || currentPage >= lastPage"
46
- title="Siguiente"
47
- aria-label="Siguiente"
48
- @click="emit('go', currentPage + 1)"
49
- >
50
- <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
51
- <path fill="currentColor" d="M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
52
- </svg>
53
- </button>
54
- <button
55
- type="button"
56
- class="page-btn"
57
- :disabled="disabled || currentPage >= lastPage"
58
- title="Final"
59
- aria-label="Final"
60
- @click="emit('go', lastPage)"
61
- >
62
- <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
63
- <path fill="currentColor" d="m5.59 7.41 1.41-1.41 6 6-6 6-1.41-1.41L10.17 12zM16 6h2v12h-2z" />
64
- </svg>
65
- </button>
66
- </footer>
67
- </template>
68
-
69
- <style scoped>
70
- .pagination {
71
- display: flex;
72
- align-items: center;
73
- justify-content: center;
74
- gap: 0.375rem;
75
- border-top: 1px solid #e2e8f0;
76
- padding: 0.875rem 1.25rem;
77
- }
78
-
79
- .pagination-label {
80
- min-width: 7.5rem;
81
- text-align: center;
82
- font-size: 0.875rem;
83
- color: #64748b;
84
- }
85
-
86
- .page-btn {
87
- display: inline-flex;
88
- align-items: center;
89
- justify-content: center;
90
- min-width: 2rem;
91
- height: 2rem;
92
- border: 1px solid #cbd5e1;
93
- border-radius: 0.375rem;
94
- background: #fff;
95
- color: #334155;
96
- cursor: pointer;
97
- }
98
-
99
- .page-btn:hover:not(:disabled) {
100
- background: #f8fafc;
101
- border-color: #94a3b8;
102
- }
103
-
104
- .page-btn:disabled {
105
- opacity: 0.45;
106
- cursor: not-allowed;
107
- }
108
-
109
- .page-icon {
110
- width: 1.125rem;
111
- height: 1.125rem;
112
- }
113
- </style>
1
+ <script setup lang="ts">
2
+ withDefaults(defineProps<{
3
+ currentPage: number
4
+ lastPage: number
5
+ disabled?: boolean
6
+ }>(), {
7
+ disabled: false,
8
+ })
9
+
10
+ const emit = defineEmits<{
11
+ go: [page: number]
12
+ }>()
13
+ </script>
14
+
15
+ <template>
16
+ <footer v-if="lastPage > 1" class="pagination">
17
+ <button
18
+ type="button"
19
+ class="page-btn"
20
+ :disabled="disabled || currentPage <= 1"
21
+ title="Inicio"
22
+ aria-label="Inicio"
23
+ @click="emit('go', 1)"
24
+ >
25
+ <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
26
+ <path fill="currentColor" d="M18.41 16.59 13.82 12l4.59-4.59L17 6l-6 6 6 6zM6 6h2v12H6z" />
27
+ </svg>
28
+ </button>
29
+ <button
30
+ type="button"
31
+ class="page-btn"
32
+ :disabled="disabled || currentPage <= 1"
33
+ title="Anterior"
34
+ aria-label="Anterior"
35
+ @click="emit('go', currentPage - 1)"
36
+ >
37
+ <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
38
+ <path fill="currentColor" d="M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z" />
39
+ </svg>
40
+ </button>
41
+ <span class="pagination-label">Página {{ currentPage }} de {{ lastPage }}</span>
42
+ <button
43
+ type="button"
44
+ class="page-btn"
45
+ :disabled="disabled || currentPage >= lastPage"
46
+ title="Siguiente"
47
+ aria-label="Siguiente"
48
+ @click="emit('go', currentPage + 1)"
49
+ >
50
+ <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
51
+ <path fill="currentColor" d="M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
52
+ </svg>
53
+ </button>
54
+ <button
55
+ type="button"
56
+ class="page-btn"
57
+ :disabled="disabled || currentPage >= lastPage"
58
+ title="Final"
59
+ aria-label="Final"
60
+ @click="emit('go', lastPage)"
61
+ >
62
+ <svg viewBox="0 0 24 24" aria-hidden="true" class="page-icon">
63
+ <path fill="currentColor" d="m5.59 7.41 1.41-1.41 6 6-6 6-1.41-1.41L10.17 12zM16 6h2v12h-2z" />
64
+ </svg>
65
+ </button>
66
+ </footer>
67
+ </template>
68
+
69
+ <style scoped>
70
+ .pagination {
71
+ display: flex;
72
+ align-items: center;
73
+ justify-content: center;
74
+ gap: 0.375rem;
75
+ border-top: 1px solid #e2e8f0;
76
+ padding: 0.875rem 1.25rem;
77
+ }
78
+
79
+ .pagination-label {
80
+ min-width: 7.5rem;
81
+ text-align: center;
82
+ font-size: 0.875rem;
83
+ color: #64748b;
84
+ }
85
+
86
+ .page-btn {
87
+ display: inline-flex;
88
+ align-items: center;
89
+ justify-content: center;
90
+ min-width: 2rem;
91
+ height: 2rem;
92
+ border: 1px solid #cbd5e1;
93
+ border-radius: 0.375rem;
94
+ background: #fff;
95
+ color: #334155;
96
+ cursor: pointer;
97
+ }
98
+
99
+ .page-btn:hover:not(:disabled) {
100
+ background: #f8fafc;
101
+ border-color: #94a3b8;
102
+ }
103
+
104
+ .page-btn:disabled {
105
+ opacity: 0.45;
106
+ cursor: not-allowed;
107
+ }
108
+
109
+ .page-icon {
110
+ width: 1.125rem;
111
+ height: 1.125rem;
112
+ }
113
+ </style>
@@ -1,27 +1,27 @@
1
- export const CATALOG_PAGE_SIZE = 50
2
-
3
- export type CatalogPageResult<T> = {
4
- pageItems: T[]
5
- currentPage: number
6
- lastPage: number
7
- total: number
8
- }
9
-
10
- /** Parte un arreglo en páginas (paginación en memoria). */
11
- export function paginateCatalogItems<T>(
12
- items: readonly T[],
13
- page: number,
14
- pageSize: number = CATALOG_PAGE_SIZE,
15
- ): CatalogPageResult<T> {
16
- const total = items.length
17
- const lastPage = Math.max(1, Math.ceil(total / pageSize) || 1)
18
- const currentPage = Math.min(Math.max(1, page), lastPage)
19
- const start = (currentPage - 1) * pageSize
20
-
21
- return {
22
- pageItems: items.slice(start, start + pageSize) as T[],
23
- currentPage,
24
- lastPage,
25
- total,
26
- }
27
- }
1
+ export const CATALOG_PAGE_SIZE = 50
2
+
3
+ export type CatalogPageResult<T> = {
4
+ pageItems: T[]
5
+ currentPage: number
6
+ lastPage: number
7
+ total: number
8
+ }
9
+
10
+ /** Parte un arreglo en páginas (paginación en memoria). */
11
+ export function paginateCatalogItems<T>(
12
+ items: readonly T[],
13
+ page: number,
14
+ pageSize: number = CATALOG_PAGE_SIZE,
15
+ ): CatalogPageResult<T> {
16
+ const total = items.length
17
+ const lastPage = Math.max(1, Math.ceil(total / pageSize) || 1)
18
+ const currentPage = Math.min(Math.max(1, page), lastPage)
19
+ const start = (currentPage - 1) * pageSize
20
+
21
+ return {
22
+ pageItems: items.slice(start, start + pageSize) as T[],
23
+ currentPage,
24
+ lastPage,
25
+ total,
26
+ }
27
+ }