@cloudron/pankow 4.3.4 → 4.3.5

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.
@@ -77,6 +77,7 @@ function onClick(event) {
77
77
  align-items: center;
78
78
  justify-content: center;
79
79
  display: inline-flex;
80
+ line-height: 1.2;
80
81
  cursor: pointer;
81
82
  border: 1px solid transparent;
82
83
  transition: background 250ms, border-color 250ms;
@@ -101,6 +102,12 @@ a.pankow-button:visited {
101
102
  margin-right: 7px;
102
103
  }
103
104
 
105
+ .pankow-button [class^="fa-"],
106
+ .pankow-button [class*=" fa-"],
107
+ .pankow-button .fa {
108
+ line-height: inherit;
109
+ }
110
+
104
111
  .pankow-button-icon-right-with-text {
105
112
  padding-left: 7px;
106
113
  }
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
 
3
3
  import { uuidv4 } from '../utils.js';
4
+ import textOverflow from '../text-overflow.js';
4
5
 
5
6
  const props = defineProps({
6
7
  label: String,
@@ -13,13 +14,15 @@ const model = defineModel({ type: Boolean });
13
14
 
14
15
  const internalId = uuidv4();
15
16
 
17
+ const vTextOverflow = textOverflow;
18
+
16
19
  </script>
17
20
 
18
21
  <template>
19
22
  <span class="pankow-checkbox">
20
23
  <input :id="id || internalId" class="pankow-checkbox-input" type="checkbox" v-model="model" :disabled="disabled" :required="$attrs['required']" @input="$emit('update:modelValue', $event.target.checked)"/>
21
24
  <slot>
22
- <label :for="id || internalId" class="pankow-checkbox-input-label">
25
+ <label :for="id || internalId" class="pankow-checkbox-input-label" v-text-overflow>
23
26
  {{ label }}
24
27
  <sup v-if="helpUrl"><a :href="helpUrl" target="_blank" tabindex="-1"><i class="fa fa-question-circle"></i></a></sup>
25
28
  </label>
package/index.js CHANGED
@@ -59,6 +59,7 @@ import gestures from './gestures.js';
59
59
  import utils from './utils.js';
60
60
  import tooltip from './tooltip.js';
61
61
  import fallbackImage from './fallbackImage.js';
62
+ import textOverflow from './text-overflow.js';
62
63
 
63
64
  export {
64
65
  BottomBar,
@@ -111,6 +112,7 @@ export {
111
112
  gestures,
112
113
  tooltip,
113
114
  fallbackImage,
115
+ textOverflow,
114
116
  utils,
115
117
  };
116
118
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cloudron/pankow",
3
3
  "private": false,
4
- "version": "4.3.4",
4
+ "version": "4.3.5",
5
5
  "description": "Vue 3 UI component library for Cloudron apps",
6
6
  "main": "index.js",
7
7
  "types": "types/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  "license": "ISC",
39
39
  "dependencies": {
40
40
  "@fontsource/inter": "^5.2.8",
41
- "@fortawesome/fontawesome-free": "^7.3.0",
41
+ "@fortawesome/fontawesome-free": "^7.3.1",
42
42
  "filesize": "^11.0.22",
43
43
  "monaco-editor": "^0.55.1",
44
44
  "online-3d-viewer": "^0.18.0"
@@ -48,13 +48,13 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@highlightjs/vue-plugin": "^2.1.0",
51
- "@unhead/vue": "^2.1.15",
51
+ "@unhead/vue": "^3.1.8",
52
52
  "@vitejs/plugin-vue": "^6.0.8",
53
53
  "highlight.js": "^11.11.1",
54
54
  "typescript": "^7.0.2",
55
- "vite": "^8.1.4",
55
+ "vite": "^8.1.5",
56
56
  "vite-ssg": "^28.3.0",
57
- "vue": "^3.5.39",
58
- "vue-router": "^5.1.0"
57
+ "vue": "^3.5.40",
58
+ "vue-router": "^5.2.0"
59
59
  }
60
60
  }
package/plugin.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { createApp } from 'vue';
2
2
  import tooltip from './tooltip.js';
3
3
  import fallbackImage from './fallbackImage.js';
4
+ import textOverflow from './text-overflow.js';
4
5
  import fetcher from './fetcher.js';
5
6
  import { setNotifyPosition } from './notifyState.js';
6
7
  import Notification from './components/Notification.vue';
@@ -11,6 +12,7 @@ export default {
11
12
  install(app, options = {}) {
12
13
  app.directive('tooltip', tooltip);
13
14
  app.directive('fallback-image', fallbackImage);
15
+ app.directive('text-overflow', textOverflow);
14
16
 
15
17
  if (options.fetcher) {
16
18
  if (options.fetcher.credentials !== undefined) {
package/style.css CHANGED
@@ -34,6 +34,8 @@
34
34
  --pankow-tooltip-background-color: #333;
35
35
  --pankow-tooltip-text-color: white;
36
36
 
37
+ --pankow-color-border: #ddd;
38
+
37
39
  --pankow-color-primary: #1a76bf;
38
40
  --pankow-color-primary-hover: #0d89ec;
39
41
  --pankow-color-primary-active: #0b7ad1;
@@ -111,6 +113,8 @@ input {
111
113
  --pankow-color-background: #1b1e21;
112
114
  --pankow-color-background-hover: #1f2326;
113
115
 
116
+ --pankow-color-border: #495057;
117
+
114
118
  --pankow-dialog-background-color: #32383e;
115
119
  --pankow-dialog-backdrop-color: rgba(0,0,0,.7);
116
120
  }
@@ -211,6 +215,33 @@ textarea[disabled]:hover {
211
215
  text-align: center;
212
216
  }
213
217
 
218
+ .pankow-text-overflow-tooltip {
219
+ position: fixed;
220
+ background: var(--pankow-color-background);
221
+ border: 1px solid var(--pankow-color-border);
222
+ border-radius: var(--pankow-border-radius);
223
+ padding: 8px 12px;
224
+ font-size: 13px;
225
+ z-index: 10000;
226
+ max-width: 400px;
227
+ white-space: normal;
228
+ word-break: break-word;
229
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
230
+ pointer-events: none;
231
+ }
232
+
233
+ @media (prefers-color-scheme: dark) {
234
+ .pankow-text-overflow-tooltip {
235
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
236
+ }
237
+ }
238
+
239
+ @media (hover: none) and (pointer: coarse) {
240
+ .pankow-text-overflow-tooltip {
241
+ display: none !important;
242
+ }
243
+ }
244
+
214
245
  .has-error {
215
246
  color: var(--pankow-color-danger);
216
247
  }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * TextOverflow Directive
3
+ *
4
+ * Shows a cursor-following tooltip overlay only when the element's text content
5
+ * is actually clipped (scrollWidth > clientWidth).
6
+ *
7
+ * Usage:
8
+ * ```
9
+ * import textOverflow from 'pankow/text-overflow';
10
+ * app.directive('text-overflow', textOverflow);
11
+ * // <div v-text-overflow>{{ longText }}</div>
12
+ * ```
13
+ */
14
+
15
+ const tooltips = {};
16
+ let id = 0;
17
+
18
+ function createOverlay() {
19
+ const el = document.createElement('div');
20
+ el.classList.add('pankow-text-overflow-tooltip');
21
+ el.style.display = 'none';
22
+ document.body.appendChild(el);
23
+ return el;
24
+ }
25
+
26
+ function isOverflowing(el) {
27
+ return el.scrollWidth > el.clientWidth;
28
+ }
29
+
30
+ /**
31
+ * Vue directive `mounted` hook.
32
+ * @param {HTMLElement} el
33
+ * @param {import('vue').DirectiveBinding} binding
34
+ * @param {import('vue').VNode} vnode
35
+ */
36
+ function mounted(el, binding, vnode) {
37
+ el.__pankow_to_id = id++;
38
+
39
+ tooltips[el.__pankow_to_id] = {
40
+ overlay: null,
41
+ text: el.textContent || '',
42
+ };
43
+
44
+ el.addEventListener('mouseenter', onMouseEnter);
45
+ el.addEventListener('mouseleave', onMouseLeave);
46
+ el.addEventListener('mousemove', onMouseMove);
47
+ }
48
+
49
+ /**
50
+ * Vue directive `updated` hook.
51
+ * @param {HTMLElement} el
52
+ * @param {import('vue').DirectiveBinding} binding
53
+ * @param {import('vue').VNode} vnode
54
+ */
55
+ function updated(el, binding, vnode) {
56
+ const state = tooltips[el.__pankow_to_id];
57
+ if (state) state.text = el.textContent || '';
58
+ }
59
+
60
+ /**
61
+ * Vue directive `beforeUnmount` hook.
62
+ * @param {HTMLElement} el
63
+ * @param {import('vue').DirectiveBinding} binding
64
+ * @param {import('vue').VNode} vnode
65
+ */
66
+ function beforeUnmount(el, binding, vnode) {
67
+ el.removeEventListener('mouseenter', onMouseEnter);
68
+ el.removeEventListener('mouseleave', onMouseLeave);
69
+ el.removeEventListener('mousemove', onMouseMove);
70
+
71
+ const state = tooltips[el.__pankow_to_id];
72
+ if (state) {
73
+ if (state.overlay) state.overlay.remove();
74
+ delete tooltips[el.__pankow_to_id];
75
+ }
76
+ }
77
+
78
+ function onMouseEnter(event) {
79
+ const el = event.currentTarget;
80
+ if (!isOverflowing(el)) return;
81
+
82
+ const state = tooltips[el.__pankow_to_id];
83
+ if (!state) return;
84
+
85
+ if (!state.overlay) state.overlay = createOverlay();
86
+ state.overlay.textContent = state.text;
87
+ state.overlay.style.display = 'block';
88
+ updatePosition(event, state);
89
+ }
90
+
91
+ function onMouseLeave(event) {
92
+ const el = event.currentTarget;
93
+ const state = tooltips[el.__pankow_to_id];
94
+ if (!state || !state.overlay) return;
95
+ state.overlay.style.display = 'none';
96
+ }
97
+
98
+ function onMouseMove(event) {
99
+ const el = event.currentTarget;
100
+ const state = tooltips[el.__pankow_to_id];
101
+ updatePosition(event, state);
102
+ }
103
+
104
+ function updatePosition(event, state) {
105
+ if (!state || !state.overlay) return;
106
+ state.overlay.style.left = (event.clientX + 10) + 'px';
107
+ state.overlay.style.top = (event.clientY + 20) + 'px';
108
+ }
109
+
110
+ /**
111
+ * Vue directive for text-overflow tooltips. Register via `app.directive('text-overflow', textOverflow)`.
112
+ * @type {import('vue').Directive}
113
+ */
114
+ const textOverflow = {
115
+ mounted,
116
+ updated,
117
+ beforeUnmount
118
+ };
119
+
120
+ export default textOverflow;
package/types/index.d.ts CHANGED
@@ -53,7 +53,8 @@ import gestures from './gestures.js';
53
53
  import utils from './utils.js';
54
54
  import tooltip from './tooltip.js';
55
55
  import fallbackImage from './fallbackImage.js';
56
- export { BottomBar, BreadCrumb, Button, ButtonGroup, ClipboardAction, ClipboardButton, CheckBox, DateTimeInput, Dialog, DirectoryView, EmailInput, FileUploader, FormGroup, InputGroup, Icon, ListItem, InputDialog, LoginView, MainLayout, MaskedInput, Menu, MenuItem, SingleSelect, MultiSelect, Notification, NumberInput, OfflineBanner, PasswordInput, Popover, ProgressBar, RadioButton, SaveIndicator, SectionItem, SideBar, SplitLayout, Spinner, Switch, TableView, TableViewActionBar, TabView, TagInput, TextInput, TextInputRaw, TopBar, TreeView, fetcher, gestures, tooltip, fallbackImage, utils, };
56
+ import textOverflow from './text-overflow.js';
57
+ export { BottomBar, BreadCrumb, Button, ButtonGroup, ClipboardAction, ClipboardButton, CheckBox, DateTimeInput, Dialog, DirectoryView, EmailInput, FileUploader, FormGroup, InputGroup, Icon, ListItem, InputDialog, LoginView, MainLayout, MaskedInput, Menu, MenuItem, SingleSelect, MultiSelect, Notification, NumberInput, OfflineBanner, PasswordInput, Popover, ProgressBar, RadioButton, SaveIndicator, SectionItem, SideBar, SplitLayout, Spinner, Switch, TableView, TableViewActionBar, TabView, TagInput, TextInput, TextInputRaw, TopBar, TreeView, fetcher, gestures, tooltip, fallbackImage, textOverflow, utils, };
57
58
  export { CheckBox as Checkbox };
58
59
  export { RadioButton as Radiobutton };
59
60
  export { BreadCrumb as Breadcrumb };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TextOverflow Directive
3
+ *
4
+ * Shows a cursor-following tooltip overlay only when the element's text content
5
+ * is actually clipped (scrollWidth > clientWidth).
6
+ *
7
+ * Usage:
8
+ * ```
9
+ * import textOverflow from 'pankow/text-overflow';
10
+ * app.directive('text-overflow', textOverflow);
11
+ * // <div v-text-overflow>{{ longText }}</div>
12
+ * ```
13
+ */
14
+ /**
15
+ * Vue directive for text-overflow tooltips. Register via `app.directive('text-overflow', textOverflow)`.
16
+ * @type {import('vue').Directive}
17
+ */
18
+ declare const textOverflow: import('vue').Directive;
19
+ export default textOverflow;