@activecollab/components 2.0.366 → 2.0.367

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.
@@ -1,8 +1,9 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["open", "className", "children"],
4
- _excluded2 = ["labels"],
5
- _excluded3 = ["value", "tooltip", "overdue"];
4
+ _excluded2 = ["value", "tooltip"],
5
+ _excluded3 = ["labels"],
6
+ _excluded4 = ["value", "tooltip", "overdue"];
6
7
  import React, { createContext, forwardRef, useCallback, useContext, useMemo, useState } from "react";
7
8
  import moment from "moment-timezone";
8
9
  import styled, { css } from "styled-components";
@@ -24,10 +25,16 @@ import { Body2, Caption1, Caption2, Header3 } from "../../components/Typography"
24
25
  import { formatHours } from "../../utils";
25
26
 
26
27
  /**
27
- * Interactive list-view column cells for the `Presentation/List view` story —
28
- * the Label, Date and Time cells with their editors, mirroring
29
- * `new-activecollab-front/src/components/ListView/columns/*`:
28
+ * Interactive list-view column cells for the `Presentation/List view` and
29
+ * `Presentation/List View ID Column` stories — the Label, Date and Time cells
30
+ * with their editors, mirroring
31
+ * `new-activecollab-front/src/components/ListView/columns/*`, plus an
32
+ * Identifier cell that only the ID-column story uses (it has no counterpart in
33
+ * the app yet):
30
34
  *
35
+ * - **Identifier** (no app equivalent): `#<id>` as a Copy Link trigger, styled
36
+ * like the Date trigger. One typography at every length — the column's width
37
+ * is what adapts to how large the identifiers get.
31
38
  * - **Label** (`columns/Label.js` + `LabelTrigger`/`LabelItems`): chips for 1–2
32
39
  * labels, dots from 3 up, `+N` past 8, and a DS `Select` picker (search,
33
40
  * colored dot + label name in the label's own colour, checkbox, "+ Add new").
@@ -88,6 +95,70 @@ const StyledListButton = styled(ListButtonBase).withConfig({
88
95
  componentId: "sc-9f4385-0"
89
96
  })(["&&{display:inline-flex;align-items:center;justify-content:flex-end;width:auto;min-width:0;max-width:100%;padding:4px 8px;overflow:visible;text-align:right;}", ""], CooltipStyle);
90
97
 
98
+ /* ================================================================== */
99
+ /* Identifier (task ID) */
100
+ /* ================================================================== */
101
+
102
+ const StyledIdValue = styled.span.withConfig({
103
+ displayName: "columns__StyledIdValue",
104
+ componentId: "sc-9f4385-1"
105
+ })(["font-family:", ";white-space:nowrap;font-variant-numeric:tabular-nums;"], SANS);
106
+ /**
107
+ * Same trigger the Date cell uses, so the id gets the identical hover outline
108
+ * and 8px inset — it is a link, not an editor, so it is always visible
109
+ * (`has-value`) rather than appearing on row hover.
110
+ *
111
+ * The typography is Caption 1 bold at every identifier length, like the Date
112
+ * value next to it; long identifiers are handled by the column's width tier,
113
+ * not by shrinking the text.
114
+ */
115
+ const IdTrigger = /*#__PURE__*/forwardRef((_ref2, ref) => {
116
+ let value = _ref2.value,
117
+ tooltip = _ref2.tooltip,
118
+ rest = _objectWithoutPropertiesLoose(_ref2, _excluded2);
119
+ return /*#__PURE__*/React.createElement(StyledListButton, _extends({}, rest, {
120
+ ref: ref,
121
+ className: "show-on-hover has-value",
122
+ "aria-label": "Copy link to task " + value,
123
+ "data-tooltip": tooltip
124
+ }), /*#__PURE__*/React.createElement(StyledIdValue, null, /*#__PURE__*/React.createElement(Caption1, {
125
+ weight: "bold",
126
+ color: "secondary"
127
+ }, value)));
128
+ });
129
+ IdTrigger.displayName = "IdTrigger";
130
+
131
+ /**
132
+ * Task identifier cell — the `#<id>` value as a copy-link control, mirroring
133
+ * how `tasks/Metadata.js` turns `Task #248` into the task's Copy Link action:
134
+ * the click writes the task URL to the clipboard and reports back so the page
135
+ * can raise the app's "Link copied to clipboard." toast (utils/copyLinkToClipboard).
136
+ * It never navigates — the row itself is the navigation target.
137
+ */
138
+ export const IdentifierCell = _ref3 => {
139
+ let identifier = _ref3.identifier,
140
+ link = _ref3.link,
141
+ onCopy = _ref3.onCopy;
142
+ const handleClick = useCallback(event => {
143
+ var _navigator$clipboard;
144
+ /* the whole row navigates to the task, so copying must not also open it */
145
+ event.preventDefault();
146
+ event.stopPropagation();
147
+ if ((_navigator$clipboard = navigator.clipboard) != null && _navigator$clipboard.writeText) {
148
+ navigator.clipboard.writeText(link).then(() => onCopy == null ? void 0 : onCopy(true)).catch(() => onCopy == null ? void 0 : onCopy(false));
149
+ return;
150
+ }
151
+ onCopy == null || onCopy(false);
152
+ }, [link, onCopy]);
153
+ return /*#__PURE__*/React.createElement("div", {
154
+ className: "col col-identifier"
155
+ }, /*#__PURE__*/React.createElement(IdTrigger, {
156
+ value: "#" + identifier,
157
+ tooltip: "Copy Link",
158
+ onClick: handleClick
159
+ }));
160
+ };
161
+
91
162
  /* ================================================================== */
92
163
  /* Labels */
93
164
  /* ================================================================== */
@@ -199,8 +270,8 @@ const LabelsContext = /*#__PURE__*/createContext({
199
270
  * Holds the label catalogue for the whole list, so a label created in one
200
271
  * task's picker shows up in every other picker too.
201
272
  */
202
- export const LabelsProvider = _ref2 => {
203
- let children = _ref2.children;
273
+ export const LabelsProvider = _ref4 => {
274
+ let children = _ref4.children;
204
275
  const _useState = useState(INITIAL_LABELS),
205
276
  labels = _useState[0],
206
277
  setLabels = _useState[1];
@@ -235,15 +306,15 @@ const useTaskLabels = () => useContext(LabelsContext);
235
306
  /* Empty state pill (mirrors EntityLabel + .entity-label in list-view.less) */
236
307
  const StyledLabelPlaceholder = styled.span.withConfig({
237
308
  displayName: "columns__StyledLabelPlaceholder",
238
- componentId: "sc-9f4385-1"
309
+ componentId: "sc-9f4385-2"
239
310
  })(["display:inline-flex;align-items:center;padding:1px 6px;border:1px solid var(--color-theme-700);border-radius:4px;.list-button.open &,.list-button:hover &{border-color:var(--color-primary-700,var(--color-primary));}"]);
240
311
  const StyledLabelItems = styled.span.withConfig({
241
312
  displayName: "columns__StyledLabelItems",
242
- componentId: "sc-9f4385-2"
313
+ componentId: "sc-9f4385-3"
243
314
  })(["display:inline-flex;align-items:center;min-width:0;> *:not(:last-child){margin-right:2px;}.rest-count{margin-left:2px;}", ""], CooltipStyle);
244
315
  const MAX_SHOWN_LABELS = 8;
245
- const LabelItems = _ref3 => {
246
- let labels = _ref3.labels;
316
+ const LabelItems = _ref5 => {
317
+ let labels = _ref5.labels;
247
318
  const showAsDot = labels.length > 2;
248
319
  let shown = labels;
249
320
  let restCount = 0;
@@ -274,9 +345,9 @@ const LabelItems = _ref3 => {
274
345
  className: "rest-count"
275
346
  }, "+", restCount) : null);
276
347
  };
277
- const LabelTrigger = /*#__PURE__*/forwardRef((_ref4, ref) => {
278
- let labels = _ref4.labels,
279
- rest = _objectWithoutPropertiesLoose(_ref4, _excluded2);
348
+ const LabelTrigger = /*#__PURE__*/forwardRef((_ref6, ref) => {
349
+ let labels = _ref6.labels,
350
+ rest = _objectWithoutPropertiesLoose(_ref6, _excluded3);
280
351
  if (labels.length === 0) {
281
352
  return /*#__PURE__*/React.createElement(StyledListButton, _extends({}, rest, {
282
353
  ref: ref,
@@ -296,10 +367,10 @@ const LabelTrigger = /*#__PURE__*/forwardRef((_ref4, ref) => {
296
367
  }));
297
368
  });
298
369
  LabelTrigger.displayName = "LabelTrigger";
299
- export const LabelCell = _ref5 => {
300
- let labelIds = _ref5.labelIds,
301
- _ref5$completed = _ref5.completed,
302
- completed = _ref5$completed === void 0 ? false : _ref5$completed;
370
+ export const LabelCell = _ref7 => {
371
+ let labelIds = _ref7.labelIds,
372
+ _ref7$completed = _ref7.completed,
373
+ completed = _ref7$completed === void 0 ? false : _ref7$completed;
303
374
  const _useTaskLabels = useTaskLabels(),
304
375
  catalog = _useTaskLabels.labels,
305
376
  labelsById = _useTaskLabels.labelsById,
@@ -388,14 +459,14 @@ const formatDateLong = value => value ? moment.unix(value).utc().format(DATE_FOR
388
459
  export const isOverdue = (dueOn, completed) => Boolean(dueOn && !completed && dueOn < todayUnix());
389
460
  const StyledDateValue = styled.span.withConfig({
390
461
  displayName: "columns__StyledDateValue",
391
- componentId: "sc-9f4385-3"
462
+ componentId: "sc-9f4385-4"
392
463
  })(["font-family:", ";white-space:nowrap;"], SANS);
393
464
 
394
465
  /* completed rows render values without a trigger, so the cell itself hosts the
395
466
  CSS tooltip */
396
467
  const StyledReadOnlyCell = styled.div.withConfig({
397
468
  displayName: "columns__StyledReadOnlyCell",
398
- componentId: "sc-9f4385-4"
469
+ componentId: "sc-9f4385-5"
399
470
  })(["padding-right:8px;", ""], CooltipStyle);
400
471
 
401
472
  /**
@@ -407,13 +478,13 @@ const StyledReadOnlyCell = styled.div.withConfig({
407
478
  */
408
479
  const StyledPickerCell = styled.div.withConfig({
409
480
  displayName: "columns__StyledPickerCell",
410
- componentId: "sc-9f4385-5"
481
+ componentId: "sc-9f4385-6"
411
482
  })(["> div{text-align:right;}"]);
412
- const DateTrigger = /*#__PURE__*/forwardRef((_ref6, ref) => {
413
- let value = _ref6.value,
414
- tooltip = _ref6.tooltip,
415
- overdue = _ref6.overdue,
416
- rest = _objectWithoutPropertiesLoose(_ref6, _excluded3);
483
+ const DateTrigger = /*#__PURE__*/forwardRef((_ref8, ref) => {
484
+ let value = _ref8.value,
485
+ tooltip = _ref8.tooltip,
486
+ overdue = _ref8.overdue,
487
+ rest = _objectWithoutPropertiesLoose(_ref8, _excluded4);
417
488
  return /*#__PURE__*/React.createElement(StyledListButton, _extends({}, rest, {
418
489
  ref: ref,
419
490
  className: value ? "show-on-hover has-value" : "show-on-hover",
@@ -425,12 +496,12 @@ const DateTrigger = /*#__PURE__*/forwardRef((_ref6, ref) => {
425
496
  }, value)) : /*#__PURE__*/React.createElement(CalendarIcon, null));
426
497
  });
427
498
  DateTrigger.displayName = "DateTrigger";
428
- export const DateCell = _ref7 => {
499
+ export const DateCell = _ref9 => {
429
500
  var _dates$from, _dates$to2;
430
- let startOn = _ref7.startOn,
431
- dueOn = _ref7.dueOn,
432
- _ref7$completed = _ref7.completed,
433
- completed = _ref7$completed === void 0 ? false : _ref7$completed;
501
+ let startOn = _ref9.startOn,
502
+ dueOn = _ref9.dueOn,
503
+ _ref9$completed = _ref9.completed,
504
+ completed = _ref9$completed === void 0 ? false : _ref9$completed;
434
505
  const _useState3 = useState({
435
506
  from: startOn,
436
507
  to: dueOn
@@ -553,11 +624,11 @@ const progressColor = percent => {
553
624
  };
554
625
  const StyledTimeValue = styled.span.withConfig({
555
626
  displayName: "columns__StyledTimeValue",
556
- componentId: "sc-9f4385-6"
627
+ componentId: "sc-9f4385-7"
557
628
  })(["display:inline-flex;align-items:center;font-family:", ";white-space:nowrap;.c-progress-pie,svg{flex-shrink:0;}.time-pie{margin-right:8px;}"], SANS);
558
- const TimeValue = _ref8 => {
559
- let tracked = _ref8.tracked,
560
- estimated = _ref8.estimated;
629
+ const TimeValue = _ref0 => {
630
+ let tracked = _ref0.tracked,
631
+ estimated = _ref0.estimated;
561
632
  const percent = timeToEstimatePercentage(tracked, estimated);
562
633
  return /*#__PURE__*/React.createElement(StyledTimeValue, null, estimated > 0 ? /*#__PURE__*/React.createElement(ProgressPie, {
563
634
  className: "time-pie",
@@ -569,10 +640,10 @@ const TimeValue = _ref8 => {
569
640
  weight: "bold"
570
641
  }, formatTrackedAndEstimated(tracked, estimated)));
571
642
  };
572
- const TimeTrigger = _ref9 => {
573
- let tracked = _ref9.tracked,
574
- estimated = _ref9.estimated,
575
- onClick = _ref9.onClick;
643
+ const TimeTrigger = _ref1 => {
644
+ let tracked = _ref1.tracked,
645
+ estimated = _ref1.estimated,
646
+ onClick = _ref1.onClick;
576
647
  const hasTime = tracked > 0 || estimated > 0;
577
648
  return /*#__PURE__*/React.createElement(StyledListButton, {
578
649
  onClick: onClick,
@@ -584,16 +655,16 @@ const TimeTrigger = _ref9 => {
584
655
  estimated: estimated
585
656
  }) : /*#__PURE__*/React.createElement(ClockAddIcon, null));
586
657
  };
587
- export const TimeCell = _ref0 => {
588
- let taskName = _ref0.taskName,
589
- _ref0$tracked = _ref0.tracked,
590
- tracked = _ref0$tracked === void 0 ? 0 : _ref0$tracked,
591
- _ref0$estimated = _ref0.estimated,
592
- estimated = _ref0$estimated === void 0 ? 0 : _ref0$estimated,
593
- users = _ref0.users,
594
- currentUserId = _ref0.currentUserId,
595
- _ref0$completed = _ref0.completed,
596
- completed = _ref0$completed === void 0 ? false : _ref0$completed;
658
+ export const TimeCell = _ref10 => {
659
+ let taskName = _ref10.taskName,
660
+ _ref10$tracked = _ref10.tracked,
661
+ tracked = _ref10$tracked === void 0 ? 0 : _ref10$tracked,
662
+ _ref10$estimated = _ref10.estimated,
663
+ estimated = _ref10$estimated === void 0 ? 0 : _ref10$estimated,
664
+ users = _ref10.users,
665
+ currentUserId = _ref10.currentUserId,
666
+ _ref10$completed = _ref10.completed,
667
+ completed = _ref10$completed === void 0 ? false : _ref10$completed;
597
668
  const _useState5 = useState(false),
598
669
  open = _useState5[0],
599
670
  setOpen = _useState5[1];
@@ -672,17 +743,17 @@ const JOB_TYPES = [{
672
743
  `Dialog` because it is 770px wide (`.time_record_form_modal_wrapper`). */
673
744
  const StyledTimeRecordPaper = styled.div.withConfig({
674
745
  displayName: "columns__StyledTimeRecordPaper",
675
- componentId: "sc-9f4385-7"
746
+ componentId: "sc-9f4385-8"
676
747
  })(["position:relative;width:770px;max-width:95vw;max-height:calc(100vh - 156px);margin:126px auto 30px auto;padding:20px 30px;overflow:auto;border-radius:8px;background-color:var(--page-paper-main);color:var(--color-theme-900);box-shadow:var(--shadow-primary);box-sizing:border-box;font-family:", ";*{box-sizing:border-box;}@media (max-width:830px){width:calc(100vw - 60px);}.trd-header{display:flex;align-items:center;justify-content:space-between;}.trd-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;margin-right:16px;font-size:1rem;font-weight:700;}.trd-date button{width:auto;}.trd-date > div{text-align:right;}.trd-divider{margin:20px 0 32px 0;border-bottom:1px solid var(--border-primary);height:1px;}.trd-body{display:flex;justify-content:space-between;position:relative;}.trd-form{width:100%;}.trd-fields{display:flex;align-items:flex-end;}.trd-hours{width:144px;margin-right:16px;flex-shrink:0;}.trd-hours .c-input-wrapper,.trd-hours input{width:100%;}.trd-field{margin-right:16px;}.trd-field:last-of-type{margin-right:20px;}.trd-field .c-label{display:block;margin-bottom:2px;}.trd-field button{width:144px;}.trd-billable{display:flex;align-items:center;margin-top:24px;}.trd-billable .c-label{margin-left:8px;cursor:pointer;}.trd-description-trigger{display:inline-flex;align-items:center;margin-top:16px;color:var(--color-secondary);font-size:14px;font-weight:500;background:none;border:none;padding:0;cursor:pointer;font-family:", ";}.trd-description-trigger svg{margin-right:4px;fill:var(--color-primary);transition:transform 200ms ease;}.trd-description-trigger.collapsed svg{transform:rotate(180deg);}.trd-textarea{width:360px;max-width:100%;margin-top:8px;font-size:12px;resize:none;}.trd-actions{display:flex;margin-top:24px;}.trd-actions .c-button:first-child{margin-right:12px;}.trd-total{position:absolute;right:0;bottom:0;display:inline-flex;align-items:center;align-self:flex-end;background:none;border:none;padding:0;cursor:pointer;}.trd-total svg{margin-right:4px;fill:var(--color-primary);transition:transform 200ms ease;}.trd-total.collapsed svg{transform:rotate(180deg);}.trd-records{margin-top:32px;border-top:1px solid var(--border-primary);}.trd-record{display:flex;align-items:center;justify-content:space-between;height:36px;border-bottom:1px solid var(--color-theme-300);}.trd-record-left{display:flex;align-items:center;gap:12px;min-width:0;}"], SANS, SANS);
677
- const TimeRecordDialog = _ref1 => {
678
- let open = _ref1.open,
679
- taskName = _ref1.taskName,
680
- users = _ref1.users,
681
- currentUserId = _ref1.currentUserId,
682
- records = _ref1.records,
683
- total = _ref1.total,
684
- onSubmit = _ref1.onSubmit,
685
- onClose = _ref1.onClose;
748
+ const TimeRecordDialog = _ref11 => {
749
+ let open = _ref11.open,
750
+ taskName = _ref11.taskName,
751
+ users = _ref11.users,
752
+ currentUserId = _ref11.currentUserId,
753
+ records = _ref11.records,
754
+ total = _ref11.total,
755
+ onSubmit = _ref11.onSubmit,
756
+ onClose = _ref11.onClose;
686
757
  const _useState7 = useState(""),
687
758
  value = _useState7[0],
688
759
  setValue = _useState7[1];