@dbcdk/react-components 0.0.118 → 0.0.120

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.
@@ -153,13 +153,13 @@
153
153
  }
154
154
 
155
155
  .default {
156
- background-color: var(--color-bg-toolbar);
156
+ background-color: var(--opac-bg-default);
157
157
  color: var(--color-fg-default);
158
158
  border-color: transparent;
159
159
  }
160
160
 
161
161
  .default:hover {
162
- background-color: var(--color-bg-toolbar-hover);
162
+ background-color: var(--opac-bg-dark);
163
163
  border-color: transparent;
164
164
  }
165
165
 
@@ -5,8 +5,10 @@ var jsxRuntime = require('react/jsx-runtime');
5
5
  var lucideReact = require('lucide-react');
6
6
  var react = require('react');
7
7
  var client = require('../../client');
8
+ var Popover = require('../../components/popover/Popover');
8
9
  var styles = require('./Lightbox.module.css');
9
10
  var Button = require('../button/Button');
11
+ var Menu = require('../menu/Menu');
10
12
 
11
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
14
 
@@ -30,7 +32,8 @@ function Lightbox({
30
32
  showDownload = true,
31
33
  getDownloadFilename,
32
34
  buttonAddition,
33
- trigger
35
+ trigger,
36
+ getContextMenuItems
34
37
  }) {
35
38
  var _a;
36
39
  const dialogRef = react.useRef(null);
@@ -119,28 +122,38 @@ function Lightbox({
119
122
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
120
123
  trigger ? trigger(openAt) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnails, children: items.map((item, i) => {
121
124
  var _a2;
122
- return /* @__PURE__ */ jsxRuntime.jsxs(
123
- "button",
124
- {
125
- type: "button",
126
- className: styles__default.default.thumbnailBtn,
127
- onClick: () => openAt(i),
128
- "aria-label": (_a2 = item.title) != null ? _a2 : `Billede ${i + 1}`,
129
- children: [
130
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnailImg, style: { height: thumbnailHeight }, children: item.thumbnail }),
131
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnailMeta, children: /* @__PURE__ */ jsxRuntime.jsx(
132
- client.MetaBar,
133
- {
134
- items: [
135
- { label: "H\xF8jde", value: item.height != null ? `${item.height}px` : "-" },
136
- { label: "Bredde", value: item.width != null ? `${item.width}px` : "-" }
137
- ]
138
- }
139
- ) })
140
- ]
141
- },
142
- i
143
- );
125
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.thumbnailCard, children: [
126
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnailMedia, children: /* @__PURE__ */ jsxRuntime.jsx(
127
+ "button",
128
+ {
129
+ type: "button",
130
+ className: styles__default.default.thumbnailBtn,
131
+ onClick: () => openAt(i),
132
+ "aria-label": (_a2 = item.title) != null ? _a2 : `Billede ${i + 1}`,
133
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnailImg, style: { height: thumbnailHeight }, children: item.thumbnail })
134
+ }
135
+ ) }),
136
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles__default.default.thumbnailFooter, children: [
137
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: styles__default.default.thumbnailMeta, children: /* @__PURE__ */ jsxRuntime.jsx(
138
+ client.MetaBar,
139
+ {
140
+ items: [
141
+ { value: item.height != null ? `H:${item.height}px` : "-" },
142
+ { value: item.width != null ? `B:${item.width}px` : "-" }
143
+ ]
144
+ }
145
+ ) }),
146
+ getContextMenuItems ? /* @__PURE__ */ jsxRuntime.jsx(
147
+ ThumbnailContextMenu,
148
+ {
149
+ item,
150
+ index: i,
151
+ open: () => openAt(i),
152
+ getItems: getContextMenuItems
153
+ }
154
+ ) : null
155
+ ] })
156
+ ] }, i);
144
157
  }) }),
145
158
  /* @__PURE__ */ jsxRuntime.jsx(
146
159
  "dialog",
@@ -215,5 +228,63 @@ function Lightbox({
215
228
  )
216
229
  ] });
217
230
  }
231
+ function ThumbnailContextMenu({
232
+ item,
233
+ index,
234
+ open,
235
+ getItems
236
+ }) {
237
+ const menuItems = getItems({ item, index, open });
238
+ if (!menuItems.length) return null;
239
+ return /* @__PURE__ */ jsxRuntime.jsx(
240
+ Popover.Popover,
241
+ {
242
+ matchTriggerWidth: false,
243
+ minWidth: "180px",
244
+ trigger: (toggle, _icon, isOpen) => {
245
+ var _a;
246
+ return /* @__PURE__ */ jsxRuntime.jsx(
247
+ Button.Button,
248
+ {
249
+ type: "button",
250
+ size: "sm",
251
+ variant: "inline",
252
+ className: styles__default.default.thumbnailMenuTrigger,
253
+ "aria-label": `Flere handlinger for ${(_a = item.title) != null ? _a : `billede ${index + 1}`}`,
254
+ "aria-haspopup": "menu",
255
+ "aria-expanded": isOpen ? true : false,
256
+ icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { size: 16 }),
257
+ onClick: (e) => {
258
+ e.stopPropagation();
259
+ toggle(e);
260
+ }
261
+ }
262
+ );
263
+ },
264
+ children: (close) => /* @__PURE__ */ jsxRuntime.jsx(Menu.Menu, { children: menuItems.map((menuItem, menuItemIndex) => /* @__PURE__ */ jsxRuntime.jsx(
265
+ Menu.Menu.Item,
266
+ {
267
+ active: menuItem.active,
268
+ selected: menuItem.selected,
269
+ disabled: menuItem.disabled,
270
+ variant: menuItem.variant,
271
+ children: /* @__PURE__ */ jsxRuntime.jsx(
272
+ "button",
273
+ {
274
+ type: "button",
275
+ onClick: (e) => {
276
+ e.stopPropagation();
277
+ menuItem.onClick();
278
+ close();
279
+ },
280
+ children: menuItem.label
281
+ }
282
+ )
283
+ },
284
+ menuItemIndex
285
+ )) })
286
+ }
287
+ );
288
+ }
218
289
 
219
290
  exports.Lightbox = Lightbox;
@@ -8,6 +8,14 @@ export type LightboxItem = {
8
8
  width?: number;
9
9
  height?: number;
10
10
  };
11
+ export type LightboxContextMenuItem = {
12
+ label: ReactNode;
13
+ onClick: () => void;
14
+ active?: boolean;
15
+ selected?: boolean;
16
+ disabled?: boolean;
17
+ variant?: 'default' | 'danger';
18
+ };
11
19
  export interface LightboxProps {
12
20
  items: LightboxItem[];
13
21
  title?: string;
@@ -17,5 +25,10 @@ export interface LightboxProps {
17
25
  getDownloadFilename?: (item: LightboxItem, index: number) => string;
18
26
  buttonAddition?: ReactNode;
19
27
  trigger?: (open: (index?: number) => void) => ReactNode;
28
+ getContextMenuItems?: (args: {
29
+ item: LightboxItem;
30
+ index: number;
31
+ open: () => void;
32
+ }) => LightboxContextMenuItem[];
20
33
  }
21
- export declare function Lightbox({ items, title, initialIndex, thumbnailHeight, showDownload, getDownloadFilename, buttonAddition, trigger, }: LightboxProps): ReactElement | null;
34
+ export declare function Lightbox({ items, title, initialIndex, thumbnailHeight, showDownload, getDownloadFilename, buttonAddition, trigger, getContextMenuItems, }: LightboxProps): ReactElement | null;
@@ -1,10 +1,12 @@
1
1
  'use client';
2
2
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
3
- import { Download, X, ChevronLeft, ChevronRight } from 'lucide-react';
3
+ import { Download, X, ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
4
4
  import { useRef, useState, useEffect, useCallback } from 'react';
5
5
  import { MetaBar } from '../../client';
6
+ import { Popover } from '../../components/popover/Popover';
6
7
  import styles from './Lightbox.module.css';
7
8
  import { Button } from '../button/Button';
9
+ import { Menu } from '../menu/Menu';
8
10
 
9
11
  function extFromMime(mime) {
10
12
  var _a;
@@ -24,7 +26,8 @@ function Lightbox({
24
26
  showDownload = true,
25
27
  getDownloadFilename,
26
28
  buttonAddition,
27
- trigger
29
+ trigger,
30
+ getContextMenuItems
28
31
  }) {
29
32
  var _a;
30
33
  const dialogRef = useRef(null);
@@ -113,28 +116,38 @@ function Lightbox({
113
116
  return /* @__PURE__ */ jsxs(Fragment, { children: [
114
117
  trigger ? trigger(openAt) : /* @__PURE__ */ jsx("div", { className: styles.thumbnails, children: items.map((item, i) => {
115
118
  var _a2;
116
- return /* @__PURE__ */ jsxs(
117
- "button",
118
- {
119
- type: "button",
120
- className: styles.thumbnailBtn,
121
- onClick: () => openAt(i),
122
- "aria-label": (_a2 = item.title) != null ? _a2 : `Billede ${i + 1}`,
123
- children: [
124
- /* @__PURE__ */ jsx("div", { className: styles.thumbnailImg, style: { height: thumbnailHeight }, children: item.thumbnail }),
125
- /* @__PURE__ */ jsx("div", { className: styles.thumbnailMeta, children: /* @__PURE__ */ jsx(
126
- MetaBar,
127
- {
128
- items: [
129
- { label: "H\xF8jde", value: item.height != null ? `${item.height}px` : "-" },
130
- { label: "Bredde", value: item.width != null ? `${item.width}px` : "-" }
131
- ]
132
- }
133
- ) })
134
- ]
135
- },
136
- i
137
- );
119
+ return /* @__PURE__ */ jsxs("div", { className: styles.thumbnailCard, children: [
120
+ /* @__PURE__ */ jsx("div", { className: styles.thumbnailMedia, children: /* @__PURE__ */ jsx(
121
+ "button",
122
+ {
123
+ type: "button",
124
+ className: styles.thumbnailBtn,
125
+ onClick: () => openAt(i),
126
+ "aria-label": (_a2 = item.title) != null ? _a2 : `Billede ${i + 1}`,
127
+ children: /* @__PURE__ */ jsx("div", { className: styles.thumbnailImg, style: { height: thumbnailHeight }, children: item.thumbnail })
128
+ }
129
+ ) }),
130
+ /* @__PURE__ */ jsxs("div", { className: styles.thumbnailFooter, children: [
131
+ /* @__PURE__ */ jsx("div", { className: styles.thumbnailMeta, children: /* @__PURE__ */ jsx(
132
+ MetaBar,
133
+ {
134
+ items: [
135
+ { value: item.height != null ? `H:${item.height}px` : "-" },
136
+ { value: item.width != null ? `B:${item.width}px` : "-" }
137
+ ]
138
+ }
139
+ ) }),
140
+ getContextMenuItems ? /* @__PURE__ */ jsx(
141
+ ThumbnailContextMenu,
142
+ {
143
+ item,
144
+ index: i,
145
+ open: () => openAt(i),
146
+ getItems: getContextMenuItems
147
+ }
148
+ ) : null
149
+ ] })
150
+ ] }, i);
138
151
  }) }),
139
152
  /* @__PURE__ */ jsx(
140
153
  "dialog",
@@ -209,5 +222,63 @@ function Lightbox({
209
222
  )
210
223
  ] });
211
224
  }
225
+ function ThumbnailContextMenu({
226
+ item,
227
+ index,
228
+ open,
229
+ getItems
230
+ }) {
231
+ const menuItems = getItems({ item, index, open });
232
+ if (!menuItems.length) return null;
233
+ return /* @__PURE__ */ jsx(
234
+ Popover,
235
+ {
236
+ matchTriggerWidth: false,
237
+ minWidth: "180px",
238
+ trigger: (toggle, _icon, isOpen) => {
239
+ var _a;
240
+ return /* @__PURE__ */ jsx(
241
+ Button,
242
+ {
243
+ type: "button",
244
+ size: "sm",
245
+ variant: "inline",
246
+ className: styles.thumbnailMenuTrigger,
247
+ "aria-label": `Flere handlinger for ${(_a = item.title) != null ? _a : `billede ${index + 1}`}`,
248
+ "aria-haspopup": "menu",
249
+ "aria-expanded": isOpen ? true : false,
250
+ icon: /* @__PURE__ */ jsx(MoreHorizontal, { size: 16 }),
251
+ onClick: (e) => {
252
+ e.stopPropagation();
253
+ toggle(e);
254
+ }
255
+ }
256
+ );
257
+ },
258
+ children: (close) => /* @__PURE__ */ jsx(Menu, { children: menuItems.map((menuItem, menuItemIndex) => /* @__PURE__ */ jsx(
259
+ Menu.Item,
260
+ {
261
+ active: menuItem.active,
262
+ selected: menuItem.selected,
263
+ disabled: menuItem.disabled,
264
+ variant: menuItem.variant,
265
+ children: /* @__PURE__ */ jsx(
266
+ "button",
267
+ {
268
+ type: "button",
269
+ onClick: (e) => {
270
+ e.stopPropagation();
271
+ menuItem.onClick();
272
+ close();
273
+ },
274
+ children: menuItem.label
275
+ }
276
+ )
277
+ },
278
+ menuItemIndex
279
+ )) })
280
+ }
281
+ );
282
+ }
212
283
 
213
284
  export { Lightbox };
@@ -5,16 +5,32 @@
5
5
  gap: var(--spacing-md);
6
6
  }
7
7
 
8
+ .thumbnailCard {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--spacing-xs);
12
+ min-width: 0;
13
+ max-width: 100%;
14
+ }
15
+
16
+ .thumbnailMedia {
17
+ position: relative;
18
+ display: flex;
19
+ min-width: 0;
20
+ max-width: 100%;
21
+ }
22
+
8
23
  .thumbnailBtn {
9
24
  background: none;
10
25
  border: none;
11
26
  padding: 0;
12
27
  cursor: pointer;
13
- display: flex;
14
- flex-direction: column;
15
- gap: var(--spacing-xs);
28
+ display: block;
16
29
  flex: none;
17
30
  text-align: left;
31
+ position: relative;
32
+ min-width: 0;
33
+ max-width: 100%;
18
34
  }
19
35
 
20
36
  .thumbnailImg {
@@ -25,6 +41,8 @@
25
41
  transition:
26
42
  transform var(--transition-fast) var(--ease-standard),
27
43
  box-shadow var(--transition-fast) var(--ease-standard);
44
+ min-width: 0;
45
+ max-width: 100%;
28
46
  }
29
47
 
30
48
  .thumbnailBtn:hover .thumbnailImg {
@@ -34,12 +52,47 @@
34
52
  .thumbnailImg > img {
35
53
  height: 100%;
36
54
  width: auto;
55
+ max-width: 100%;
37
56
  display: block;
38
57
  }
39
58
 
40
59
  .thumbnailMeta {
60
+ flex: 1 1 auto;
41
61
  display: flex;
42
62
  gap: var(--spacing-2xs);
63
+ min-width: 0;
64
+ max-width: 100%;
65
+ }
66
+
67
+ .thumbnailMeta > div {
68
+ min-width: 0;
69
+ max-width: 100%;
70
+ overflow: hidden;
71
+ }
72
+
73
+ .thumbnailMeta > div > span,
74
+ .thumbnailMeta > div > span > span {
75
+ min-width: 0;
76
+ }
77
+
78
+ .thumbnailMeta > div > span:not([aria-hidden='true']) {
79
+ max-width: 100%;
80
+ overflow: hidden;
81
+ white-space: nowrap;
82
+ text-overflow: ellipsis;
83
+ }
84
+
85
+ .thumbnailFooter {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: var(--spacing-xs);
89
+ min-width: 0;
90
+ max-width: 100%;
91
+ }
92
+
93
+ .thumbnailMenuTrigger {
94
+ flex: 0 0 auto;
95
+ min-width: 0;
43
96
  }
44
97
 
45
98
  .dialog {
@@ -17,6 +17,9 @@ const sizeTokenMap = {
17
17
  md: "var(--component-size-md)",
18
18
  lg: "var(--component-size-lg)"
19
19
  };
20
+ function formatNumberDa(value) {
21
+ return value.toLocaleString("da-DK");
22
+ }
20
23
  function SegmentWithTooltip({
21
24
  seg,
22
25
  index,
@@ -77,7 +80,7 @@ const SegmentedProgressBar = ({
77
80
  const autoNumbers = (() => {
78
81
  const base = segments.map((s) => s.value || 0);
79
82
  if (showRemainder) base.push(remainder);
80
- return base.join("/");
83
+ return base.map(formatNumberDa).join("/");
81
84
  })();
82
85
  const filteredSegments = computedSegments.filter((x) => x.value > 0);
83
86
  const rootClass = [styles__default.default.container, className].filter(Boolean).join(" ");
@@ -11,6 +11,9 @@ const sizeTokenMap = {
11
11
  md: "var(--component-size-md)",
12
12
  lg: "var(--component-size-lg)"
13
13
  };
14
+ function formatNumberDa(value) {
15
+ return value.toLocaleString("da-DK");
16
+ }
14
17
  function SegmentWithTooltip({
15
18
  seg,
16
19
  index,
@@ -71,7 +74,7 @@ const SegmentedProgressBar = ({
71
74
  const autoNumbers = (() => {
72
75
  const base = segments.map((s) => s.value || 0);
73
76
  if (showRemainder) base.push(remainder);
74
- return base.join("/");
77
+ return base.map(formatNumberDa).join("/");
75
78
  })();
76
79
  const filteredSegments = computedSegments.filter((x) => x.value > 0);
77
80
  const rootClass = [styles.container, className].filter(Boolean).join(" ");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dbcdk/react-components",
3
- "version": "0.0.118",
3
+ "version": "0.0.120",
4
4
  "description": "Reusable React components for DBC projects",
5
5
  "license": "ISC",
6
6
  "author": "",