@signature.digital/catalog 1.7.0 → 1.9.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.
Files changed (45) hide show
  1. package/dist_ts_web/00_commitinfo_data.js +3 -3
  2. package/dist_ts_web/elements/index.d.ts +1 -0
  3. package/dist_ts_web/elements/index.js +3 -1
  4. package/dist_ts_web/elements/sdig-app-shell/index.d.ts +1 -0
  5. package/dist_ts_web/elements/sdig-app-shell/index.js +2 -0
  6. package/dist_ts_web/elements/sdig-app-shell/sdig-app-shell.d.ts +38 -0
  7. package/dist_ts_web/elements/sdig-app-shell/sdig-app-shell.js +309 -0
  8. package/dist_ts_web/elements/sdig-signbox/sdig-signbox.d.ts +1 -0
  9. package/dist_ts_web/elements/sdig-signbox/sdig-signbox.js +28 -9
  10. package/dist_ts_web/elements/sdig-signpad/sdig-signpad.d.ts +9 -2
  11. package/dist_ts_web/elements/sdig-signpad/sdig-signpad.js +23 -5
  12. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-audit.js +5 -5
  13. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-compose.d.ts +1 -0
  14. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-compose.js +18 -6
  15. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-developers.js +13 -15
  16. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-inbox.js +14 -13
  17. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-sign.d.ts +3 -0
  18. package/dist_ts_web/elements/sdig-workspace/sdig-workspace-sign.js +55 -18
  19. package/dist_ts_web/elements/sdig-workspace/sdig-workspace.js +28 -28
  20. package/dist_ts_web/elements/sdig-workspace/sdig-workspace.shared.js +44 -42
  21. package/dist_ts_web/plugins.d.ts +3 -3
  22. package/dist_ts_web/plugins.js +3 -4
  23. package/package.json +15 -21
  24. package/readme.md +54 -2
  25. package/ts_web/00_commitinfo_data.ts +2 -2
  26. package/ts_web/elements/index.ts +3 -0
  27. package/ts_web/elements/sdig-app-shell/index.ts +1 -0
  28. package/ts_web/elements/sdig-app-shell/sdig-app-shell.ts +200 -0
  29. package/ts_web/elements/sdig-signbox/sdig-signbox.ts +26 -8
  30. package/ts_web/elements/sdig-signpad/sdig-signpad.ts +27 -6
  31. package/ts_web/elements/sdig-workspace/sdig-workspace-audit.ts +4 -4
  32. package/ts_web/elements/sdig-workspace/sdig-workspace-compose.ts +16 -5
  33. package/ts_web/elements/sdig-workspace/sdig-workspace-developers.ts +12 -14
  34. package/ts_web/elements/sdig-workspace/sdig-workspace-inbox.ts +13 -12
  35. package/ts_web/elements/sdig-workspace/sdig-workspace-sign.ts +53 -17
  36. package/ts_web/elements/sdig-workspace/sdig-workspace.shared.ts +44 -41
  37. package/ts_web/elements/sdig-workspace/sdig-workspace.ts +27 -27
  38. package/ts_web/plugins.ts +3 -4
  39. package/.smartconfig.json +0 -82
  40. package/dist_bundle/bundle.js +0 -6214
  41. package/dist_bundle/bundle.js.map +0 -7
  42. package/dist_bundle/index.html +0 -28
  43. package/dist_watch/bundle.js +0 -135739
  44. package/dist_watch/bundle.js.map +0 -7
  45. package/dist_watch/index.html +0 -28
@@ -20,10 +20,10 @@ export class SdigWorkspaceInbox extends DeesElement {
20
20
 
21
21
  public static styles = [workspaceBaseStyles, css`
22
22
  .filterbar { padding: 14px 24px; border-bottom: 1px solid var(--border-subtle); display: flex; align-items: center; gap: 8px; }
23
- .searchbox { display: flex; align-items: center; gap: 8px; padding: 0 10px; height: 32px; width: 280px; background: var(--bg-input); border: 1px solid var(--border); border-radius: 6px; }
23
+ .searchbox { display: flex; align-items: center; gap: 8px; padding: 0 10px; height: 32px; width: 280px; background: var(--bg-input); border: 1px solid var(--border); border-radius: 8px; }
24
24
  .searchbox input { flex: 1; min-width: 0; background: transparent; border: none; outline: none; color: var(--text); font-size: 12px; }
25
- .segmented { display: flex; gap: 2px; padding: 2px; background: var(--bg-el); border-radius: 6px; border: 1px solid var(--border-subtle); }
26
- .segmented button { padding: 4px 10px; font-size: 11px; font-weight: 500; border-radius: 4px; background: transparent; color: var(--text-muted); display: inline-flex; align-items: center; gap: 5px; }
25
+ .segmented { display: flex; gap: 2px; padding: 2px; background: var(--bg-el); border-radius: 8px; border: 1px solid var(--border-subtle); }
26
+ .segmented button { padding: 4px 10px; font-size: 11.5px; font-weight: 510; border-radius: 6px; background: transparent; color: var(--text-muted); display: inline-flex; align-items: center; gap: 5px; }
27
27
  .segmented button.active { background: var(--bg-card); color: var(--text); box-shadow: inset 0 0 0 1px var(--border); }
28
28
  .doc-table { min-width: 880px; }
29
29
  .doc-head, .doc-row { display: grid; grid-template-columns: 32px minmax(220px,2.4fr) 150px 160px 90px 60px 32px; align-items: center; gap: 14px; padding: 0 16px; }
@@ -32,7 +32,7 @@ export class SdigWorkspaceInbox extends DeesElement {
32
32
  .doc-row.compact { height: 48px; }
33
33
  .doc-row:last-child { border-bottom: 0; }
34
34
  .doc-row:hover { background: var(--row-hover); }
35
- .doc-icon { width: 28px; height: 32px; border-radius: 4px; background: var(--bg-input); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; }
35
+ .doc-icon { width: 28px; height: 32px; border-radius: 6px; background: var(--bg-input); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; }
36
36
  .doc-title { font-size: 13px; color: var(--text); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
37
37
  .doc-meta { margin-top: 2px; font-size: 11px; color: var(--text-muted); }
38
38
  .recipient-stack { display: flex; align-items: center; }
@@ -68,7 +68,8 @@ export class SdigWorkspaceInbox extends DeesElement {
68
68
  bubbles: true,
69
69
  composed: true,
70
70
  }));
71
- requestWorkspaceView(this, doc.status === 'signed' ? 'audit' : 'sign');
71
+ const view = doc.status === 'draft' ? 'compose' : doc.status === 'signed' || doc.status === 'declined' ? 'audit' : 'sign';
72
+ requestWorkspaceView(this, view);
72
73
  }
73
74
 
74
75
  public render(): TemplateResult {
@@ -84,10 +85,10 @@ export class SdigWorkspaceInbox extends DeesElement {
84
85
 
85
86
  return html`
86
87
  ${topBar({
87
- breadcrumb: ['signature.digital', 'Lossless GmbH', 'Inbox'],
88
+ breadcrumb: ['signature.digital', 'Example workspace', 'Inbox'],
88
89
  title: 'Inbox',
89
90
  subtitle: pill(`${attentionCount} need attention`, 'info'),
90
- actions: html`${actionButton('Import', 'outline', 'upload')}${actionButton('New document', 'primary', 'plus', () => requestWorkspaceView(this, 'compose'))}`,
91
+ actions: html`${actionButton('Import', 'outline', 'upload', () => this.dispatchEvent(new CustomEvent('import-request', { bubbles: true, composed: true })))}${actionButton('New document', 'primary', 'plus', () => requestWorkspaceView(this, 'compose'))}`,
91
92
  })}
92
93
  <div class="filterbar">
93
94
  <div class="searchbox">${icon('search', 13)}<input .value=${this.search} @input=${(event: Event) => this.search = (event.target as HTMLInputElement).value} placeholder="Search documents, recipients, IDs..." /><span class="mono" style="font-size: 10px; color: var(--text-dim); border: 1px solid var(--border); border-radius: 3px; padding: 1px 5px;">⌘K</span></div>
@@ -113,11 +114,11 @@ export class SdigWorkspaceInbox extends DeesElement {
113
114
  </div>
114
115
  <div class="stats-grid">
115
116
  ${[
116
- { label: 'Sent this month', value: '127', delta: '+24%', icon: 'send' },
117
- { label: 'Avg time to sign', value: '4.2h', delta: '-18%', icon: 'clock' },
118
- { label: 'Completion rate', value: '94.1%', delta: '+2.1%', icon: 'check' },
119
- { label: 'API signatures', value: '2,481', delta: '+312', icon: 'code' },
120
- ].map((metric) => html`<div class="card metric-card"><div style="display: flex; justify-content: space-between; margin-bottom: 12px;">${icon(metric.icon, 14)}<span class="mono" style="font-size: 10px; color: var(--success);">${metric.delta}</span></div><div class="metric-value">${metric.value}</div><div style="font-size: 11px; color: var(--text-muted); margin-top: 2px;">${metric.label}</div></div>`)}
117
+ { label: 'Documents', value: documents.length, icon: 'file' },
118
+ { label: 'Awaiting signatures', value: attentionCount, icon: 'clock' },
119
+ { label: 'Completed', value: documents.filter((document) => document.status === 'signed').length, icon: 'check' },
120
+ { label: 'Drafts', value: documents.filter((document) => document.status === 'draft').length, icon: 'code' },
121
+ ].map((metric) => html`<div class="card metric-card"><div style="display: flex; justify-content: space-between; margin-bottom: 12px;">${icon(metric.icon, 14)}<span class="mono" style="font-size: 10px; color: var(--text-muted);">current</span></div><div class="metric-value">${metric.value}</div><div style="font-size: 11px; color: var(--text-muted); margin-top: 2px;">${metric.label}</div></div>`)}
121
122
  </div>
122
123
  </div>
123
124
  `;
@@ -29,7 +29,13 @@ export class SdigWorkspaceSign extends DeesElement {
29
29
  `];
30
30
 
31
31
  private get signFields() {
32
- return this.fields.slice(0, 3);
32
+ return this.fields;
33
+ }
34
+
35
+ private get activeField(): IFieldPlacement | undefined {
36
+ return this.signFields.find((field) => field.id === this.activeFieldId && !this.signedFieldIds.includes(field.id))
37
+ || this.signFields.find((field) => !this.signedFieldIds.includes(field.id))
38
+ || this.signFields[0];
33
39
  }
34
40
 
35
41
  private fieldIcon(type: IFieldPlacement['type']): string {
@@ -39,29 +45,59 @@ export class SdigWorkspaceSign extends DeesElement {
39
45
  }
40
46
 
41
47
  private signField(fieldId: string) {
42
- if (!this.signedFieldIds.includes(fieldId)) {
43
- this.signedFieldIds = [...this.signedFieldIds, fieldId];
44
- }
45
- const next = this.signFields.find((field) => !this.signedFieldIds.includes(field.id) && field.id !== fieldId);
48
+ const field = this.signFields.find((currentField) => currentField.id === fieldId);
49
+ if (!field || this.signedFieldIds.includes(fieldId)) return;
50
+ this.signedFieldIds = [...this.signedFieldIds, fieldId];
51
+ this.dispatchEvent(new CustomEvent('field-signed', {
52
+ detail: { document: this.document, field, signedFieldIds: this.signedFieldIds },
53
+ bubbles: true,
54
+ composed: true,
55
+ }));
56
+ const next = this.signFields.find((currentField) => !this.signedFieldIds.includes(currentField.id));
46
57
  if (next) this.activeFieldId = next.id;
47
58
  }
48
59
 
60
+ private emitSigningComplete() {
61
+ if (this.signedFieldIds.length !== this.signFields.length) return;
62
+ this.dispatchEvent(new CustomEvent('signing-complete', {
63
+ detail: {
64
+ document: this.document,
65
+ fields: this.signFields,
66
+ signedFieldIds: this.signedFieldIds,
67
+ completedAt: Date.now(),
68
+ },
69
+ bubbles: true,
70
+ composed: true,
71
+ }));
72
+ }
73
+
74
+ private handlePrimaryAction() {
75
+ if (!this.signFields.length) return;
76
+ if (this.signedFieldIds.length === this.signFields.length) {
77
+ this.emitSigningComplete();
78
+ return;
79
+ }
80
+ const activeField = this.activeField;
81
+ if (activeField) this.signField(activeField.id);
82
+ }
83
+
49
84
  private renderSignedValue(field: IFieldPlacement): TemplateResult {
50
- if (field.type === 'signature') return html`<span style="font-family: 'Plus Jakarta Sans', cursive; font-size: 22px; font-weight: 600; font-style: italic; color: hsl(220 50% 30%);">Sarah Chen</span>`;
51
- if (field.type === 'date') return html`<span class="mono" style="font-size: 12px; color: hsl(0 0% 18%);">2026-05-02</span>`;
52
- return html`<span style="font-size: 12px; color: hsl(0 0% 18%);">Sarah Chen</span>`;
85
+ if (field.type === 'signature') return html`<span style="font-size: 12px; font-weight: 600; color: hsl(220 50% 30%);">Signature captured</span>`;
86
+ if (field.type === 'date') return html`<span class="mono" style="font-size: 12px; color: hsl(0 0% 18%);">Date captured</span>`;
87
+ return html`<span style="font-size: 12px; color: hsl(0 0% 18%);">Completed</span>`;
53
88
  }
54
89
 
55
90
  public render(): TemplateResult {
56
91
  const document = this.document || demoDocuments[0];
57
92
  const completed = this.signedFieldIds.length;
58
- const progress = Math.round((completed / this.signFields.length) * 100);
59
- const activeField = this.signFields.find((field) => field.id === this.activeFieldId) || this.signFields[0];
93
+ const total = this.signFields.length;
94
+ const progress = total ? Math.round((completed / total) * 100) : 0;
95
+ const activeField = this.activeField;
60
96
 
61
97
  return html`
62
98
  <div class="recipient-header">
63
99
  <div style="display: flex; align-items: center; gap: 12px;"><span class="logomark">s</span><div><div style="font-size: 12px; font-weight: 600;">${document.title}</div><div class="mono" style="font-size: 10px; color: var(--text-muted);">From ${document.sender} · ${document.id} · ${document.pages} pages</div></div></div>
64
- <div class="actions"><span class="pill success">${icon('shield', 12)} Verified sender · DKIM ✓</span>${actionButton('Decline', 'outline')}${actionButton('PDF', 'outline', 'download')}</div>
100
+ <div class="actions"><span class="pill info">${icon('shield', 12)} Sender details supplied by host</span>${actionButton('Decline', 'outline')}${actionButton('PDF', 'outline', 'download')}</div>
65
101
  </div>
66
102
  <div class="progress-track"><div class="progress-fill" style="width: ${progress}%"></div></div>
67
103
  <div class="sign-layout">
@@ -70,23 +106,23 @@ export class SdigWorkspaceSign extends DeesElement {
70
106
  ${fakeDocument()}
71
107
  ${this.signFields.map((field) => {
72
108
  const filled = this.signedFieldIds.includes(field.id);
73
- const active = this.activeFieldId === field.id && !filled;
109
+ const active = activeField?.id === field.id && !filled;
74
110
  return html`<div class="field-box ${active ? 'selected' : ''}" style="--x: ${field.x}px; --y: ${field.y}px; --w: ${field.w}px; --h: ${field.h}px; --field-color: ${filled ? 'transparent' : 'var(--accent)'}; color: ${filled ? 'hsl(220 50% 30%)' : 'var(--accent)'}; background: ${filled ? 'transparent' : 'color-mix(in srgb, var(--accent) 12%, transparent)'};" @click=${() => !filled ? this.signField(field.id) : undefined}>${filled ? this.renderSignedValue(field) : html`${icon(this.fieldIcon(field.type), 12)}<span>${active ? html`<span style="display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); animation: pulse 1.4s infinite;"></span>` : ''}${field.label}</span>`}</div>`;
75
111
  })}
76
112
  <div class="mono" style="position: absolute; bottom: 14px; right: 18px; font-size: 9px; color: hsl(0 0% 60%);">Page 1 of ${document.pages}</div>
77
113
  </div>
78
114
  </div>
79
115
  <div class="sign-panel">
80
- <div style="display: flex; align-items: center; gap: 8px;"><span class="avatar" style="background: #60a5fa;">SC</span><div><div style="font-size: 13px; font-weight: 600;">Hi, Sarah</div><div class="mono" style="font-size: 10px; color: var(--text-muted);">sarah@acme.com</div></div></div>
81
- <div class="card" style="padding: 14px; margin-top: 16px;"><div class="label-upper">Your progress</div><div style="font-size: 24px; font-weight: 700;">${completed} <span style="color: var(--text-muted); font-weight: 400;">/ ${this.signFields.length}</span></div><div style="font-size: 11px; color: var(--text-muted); margin-top: 2px;">${this.signFields.length - completed === 0 ? 'All fields complete' : `${this.signFields.length - completed} fields remaining`}</div><div class="progress-track" style="margin-top: 12px;"><div class="progress-fill" style="width: ${progress}%"></div></div></div>
116
+ <div style="display: flex; align-items: center; gap: 8px;"><span class="avatar" style="background: #60a5fa;">SG</span><div><div style="font-size: 13px; font-weight: 600;">Signing session</div><div class="mono" style="font-size: 10px; color: var(--text-muted);">${document.id}</div></div></div>
117
+ <div class="card" style="padding: 14px; margin-top: 16px;"><div class="label-upper">Your progress</div><div style="font-size: 24px; font-weight: 700;">${completed} <span style="color: var(--text-muted); font-weight: 400;">/ ${total}</span></div><div style="font-size: 11px; color: var(--text-muted); margin-top: 2px;">${total === 0 ? 'No fields assigned' : total - completed === 0 ? 'All fields complete' : `${total - completed} fields remaining`}</div><div class="progress-track" style="margin-top: 12px;"><div class="progress-fill" style="width: ${progress}%"></div></div></div>
82
118
  <div style="margin-top: 20px;" class="label-upper">Step by step</div>
83
119
  ${this.signFields.map((field, index) => {
84
120
  const filled = this.signedFieldIds.includes(field.id);
85
- const active = this.activeFieldId === field.id && !filled;
121
+ const active = activeField?.id === field.id && !filled;
86
122
  return html`<div class="recipient-line ${active ? 'active' : ''}" @click=${() => !filled ? this.activeFieldId = field.id : undefined}><span class="avatar" style="width: 22px; height: 22px; background: ${filled ? 'var(--success)' : active ? 'var(--accent)' : 'var(--bg-input)'}; color: ${filled || active ? 'white' : 'var(--text-muted)'};">${filled ? '✓' : index + 1}</span><div style="flex: 1;"><div style="font-size: 12px; font-weight: 500; text-decoration: ${filled ? 'line-through' : 'none'};">${field.label}</div><div class="mono" style="font-size: 10px; color: var(--text-muted);">${field.type} · page ${field.page}</div></div>${active ? icon('chevronRight', 12) : ''}</div>`;
87
123
  })}
88
- <button class="btn primary" style="width: 100%; height: 44px; margin-top: 20px;" @click=${() => this.signField(activeField.id)}>${completed === this.signFields.length ? 'Finish & submit' : `Continue - ${activeField.label}`}</button>
89
- <div style="margin-top: 12px; padding: 10px; font-size: 10px; color: var(--text-muted); line-height: 1.5; text-align: center; border-radius: 6px; background: var(--bg-el);">By signing, you agree to the ESIGN Act & eIDAS terms.<br /><span class="mono">IP 81.221.4.18 · Brussels, BE</span></div>
124
+ <button class="btn primary" style="width: 100%; height: 44px; margin-top: 20px;" ?disabled=${total === 0} @click=${() => this.handlePrimaryAction()}>${total === 0 ? 'No fields to sign' : completed === total ? 'Finish & submit' : `Continue - ${activeField?.label || 'next field'}`}</button>
125
+ <div style="margin-top: 12px; padding: 10px; font-size: 10px; color: var(--text-muted); line-height: 1.5; text-align: center; border-radius: 6px; background: var(--bg-el);">Field completion is captured locally until the host application submits it through a signing API.</div>
90
126
  </div>
91
127
  </div>
92
128
  `;
@@ -59,7 +59,7 @@ export const demoDocuments: IDocumentRow[] = [
59
59
  export const demoRecipients: IRecipient[] = [
60
60
  { id: 0, name: 'Sarah Chen', email: 'sarah@acme.com', color: '#60a5fa', order: 1, role: 'signer' },
61
61
  { id: 1, name: 'David Park', email: 'd.park@acme.com', color: '#fbbf24', order: 2, role: 'signer' },
62
- { id: 2, name: 'Philipp K.', email: 'philipp@lossless.com', color: '#3b82f6', order: 3, role: 'updates' },
62
+ { id: 2, name: 'Alex Example', email: 'alex@example.test', color: '#007aff', order: 3, role: 'copy' },
63
63
  ];
64
64
 
65
65
  export const demoFields: IFieldPlacement[] = [
@@ -77,13 +77,14 @@ export const workspaceBaseStyles = css`
77
77
  min-height: 0;
78
78
  color: var(--text);
79
79
  background: var(--bg);
80
- font-family: Geist, Inter, Roboto, -apple-system, BlinkMacSystemFont, sans-serif;
80
+ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
81
81
  font-feature-settings: 'cv11', 'tnum', 'cv05' 1;
82
82
  }
83
83
 
84
84
  * { box-sizing: border-box; }
85
85
  button, input, textarea { font: inherit; }
86
86
  button { border: 0; cursor: pointer; }
87
+ button:disabled { cursor: not-allowed; opacity: 0.52; }
87
88
  dees-icon { flex-shrink: 0; }
88
89
 
89
90
  .mono {
@@ -99,7 +100,8 @@ export const workspaceBaseStyles = css`
99
100
  align-items: center;
100
101
  justify-content: space-between;
101
102
  border-bottom: 1px solid var(--border-subtle);
102
- background: var(--bg);
103
+ background: color-mix(in srgb, var(--bg) 72%, transparent);
104
+ backdrop-filter: saturate(180%) blur(20px);
103
105
  gap: 12px;
104
106
  }
105
107
 
@@ -122,10 +124,10 @@ export const workspaceBaseStyles = css`
122
124
  }
123
125
 
124
126
  .top-title > span:first-child {
125
- font-family: 'Plus Jakarta Sans', Inter, sans-serif;
126
- font-size: 18px;
127
- font-weight: 600;
128
- letter-spacing: -0.02em;
127
+ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
128
+ font-size: 19px;
129
+ font-weight: 640;
130
+ letter-spacing: -0.022em;
129
131
  white-space: nowrap;
130
132
  overflow: hidden;
131
133
  text-overflow: ellipsis;
@@ -141,7 +143,7 @@ export const workspaceBaseStyles = css`
141
143
  .btn {
142
144
  height: 34px;
143
145
  padding: 0 14px;
144
- border-radius: 6px;
146
+ border-radius: 7px;
145
147
  font-size: 13px;
146
148
  font-weight: 500;
147
149
  letter-spacing: -0.01em;
@@ -216,7 +218,7 @@ export const workspaceBaseStyles = css`
216
218
  .card {
217
219
  background: var(--bg-card);
218
220
  border: 1px solid var(--border);
219
- border-radius: 8px;
221
+ border-radius: 12px;
220
222
  overflow: hidden;
221
223
  }
222
224
 
@@ -341,23 +343,24 @@ export const workspaceBaseStyles = css`
341
343
  `;
342
344
 
343
345
  export function icon(name: string, size = 14): TemplateResult {
344
- const iconMap: Record<string, string> = {
345
- inbox: 'lucide:Inbox', plus: 'lucide:Plus', folder: 'lucide:Folder', shield: 'lucide:Shield', code: 'lucide:Code2',
346
- user: 'lucide:User', settings: 'lucide:Settings', upload: 'lucide:Upload', file: 'lucide:FileText', sign: 'lucide:PenTool',
347
- clock: 'lucide:Clock', search: 'lucide:Search', more: 'lucide:MoreHorizontal', send: 'lucide:Send', check: 'lucide:Check',
348
- eye: 'lucide:Eye', calendar: 'lucide:Calendar', type: 'lucide:Type', download: 'lucide:Download', hash: 'lucide:Hash',
349
- github: 'lucide:GitBranch', git: 'lucide:GitBranch', server: 'lucide:Server', star: 'lucide:Star', sparkle: 'lucide:Sparkles',
350
- chevronRight: 'lucide:ChevronRight', chevronDown: 'lucide:ChevronDown', x: 'lucide:X', activity: 'lucide:Activity',
351
- };
352
- return html`<dees-icon .icon=${iconMap[name] || iconMap.file} style="font-size: ${size}px;"></dees-icon>`;
346
+ return html`<dees-icon .icon=${iconMap[name] || iconMap.file} .iconSize=${size}></dees-icon>`;
353
347
  }
354
348
 
349
+ const iconMap: Record<string, string> = {
350
+ inbox: 'lucide:Inbox', plus: 'lucide:Plus', folder: 'lucide:Folder', shield: 'lucide:Shield', code: 'lucide:Code2',
351
+ user: 'lucide:User', settings: 'lucide:Settings', upload: 'lucide:Upload', file: 'lucide:FileText', sign: 'lucide:PenTool',
352
+ clock: 'lucide:Clock', search: 'lucide:Search', more: 'lucide:MoreHorizontal', send: 'lucide:Send', check: 'lucide:Check',
353
+ eye: 'lucide:Eye', calendar: 'lucide:Calendar', type: 'lucide:Type', download: 'lucide:Download', hash: 'lucide:Hash',
354
+ github: 'lucide:Github', git: 'lucide:GitBranch', server: 'lucide:Server', star: 'lucide:Star', sparkle: 'lucide:Sparkles',
355
+ chevronRight: 'lucide:ChevronRight', chevronDown: 'lucide:ChevronDown', x: 'lucide:X', activity: 'lucide:Activity',
356
+ };
357
+
355
358
  export function pill(label: string, tone: 'default' | 'success' | 'warning' | 'error' | 'info' = 'default', dot = false): TemplateResult {
356
359
  return html`<span class="pill ${tone} ${dot ? 'dot' : ''}">${label}</span>`;
357
360
  }
358
361
 
359
362
  export function actionButton(label: string, variant: 'primary' | 'outline' | 'ghost' = 'outline', iconName?: string, onClick?: () => void): TemplateResult {
360
- return html`<button class="btn ${variant}" @click=${onClick || (() => undefined)}>${iconName ? icon(iconName, 13) : ''}${label}</button>`;
363
+ return html`<button class="btn ${variant}" ?disabled=${!onClick} title=${onClick ? '' : 'This action must be wired by the host application.'} @click=${onClick}>${iconName ? icon(iconName, 13) : ''}${label}</button>`;
361
364
  }
362
365
 
363
366
  export function topBar(config: { breadcrumb: string[]; title: string; subtitle?: TemplateResult; actions?: TemplateResult }): TemplateResult {
@@ -374,9 +377,9 @@ export function topBar(config: { breadcrumb: string[]; title: string; subtitle?:
374
377
  `;
375
378
  }
376
379
 
377
- export function workspaceDemoFrame(content: TemplateResult, theme: TWorkspaceTheme = 'dark'): TemplateResult {
380
+ export function workspaceDemoFrame(content: TemplateResult, theme: TWorkspaceTheme = 'light'): TemplateResult {
378
381
  const darkVars = `
379
- --accent: #3b82f6;
382
+ --accent: #007aff;
380
383
  --bg: hsl(0 0% 3.9%);
381
384
  --bg-el: hsl(0 0% 6%);
382
385
  --bg-card: hsl(0 0% 7%);
@@ -396,39 +399,39 @@ export function workspaceDemoFrame(content: TemplateResult, theme: TWorkspaceThe
396
399
  --error: #ef4444;
397
400
  `;
398
401
  const lightVars = `
399
- --accent: #3b82f6;
400
- --bg: hsl(0 0% 99%);
401
- --bg-el: hsl(0 0% 97%);
402
+ --accent: #007aff;
403
+ --bg: hsl(0 0% 100%);
404
+ --bg-el: hsl(240 9% 96.5%);
402
405
  --bg-card: hsl(0 0% 100%);
403
- --bg-input: hsl(0 0% 98%);
404
- --border: hsl(0 0% 90%);
405
- --border-subtle: hsl(0 0% 93%);
406
- --border-strong: hsl(0 0% 80%);
407
- --text: hsl(0 0% 9%);
408
- --text-sec: hsl(0 0% 32%);
409
- --text-muted: hsl(0 0% 45%);
410
- --text-dim: hsl(0 0% 62%);
411
- --hover: rgba(0,0,0,0.04);
412
- --hover-subtle: rgba(0,0,0,0.02);
413
- --row-hover: rgba(0,0,0,0.02);
414
- --success: #16a34a;
415
- --warning: #d97706;
416
- --error: #dc2626;
406
+ --bg-input: hsl(0 0% 100%);
407
+ --border: hsl(240 6% 89%);
408
+ --border-subtle: hsl(240 6% 92.5%);
409
+ --border-strong: hsl(240 6% 80%);
410
+ --text: hsl(240 6% 11%);
411
+ --text-sec: hsl(240 4% 34%);
412
+ --text-muted: hsl(240 3% 52%);
413
+ --text-dim: hsl(240 3% 66%);
414
+ --hover: rgba(0,0,0,0.05);
415
+ --hover-subtle: rgba(0,0,0,0.028);
416
+ --row-hover: rgba(0,0,0,0.028);
417
+ --success: #34c759;
418
+ --warning: #ff9500;
419
+ --error: #ff3b30;
417
420
  `;
418
421
 
419
- return html`<div style="${theme === 'dark' ? darkVars : lightVars} height: 720px; min-height: 720px; background: var(--bg); color: var(--text); overflow: hidden; font-family: Geist, Inter, Roboto, -apple-system, BlinkMacSystemFont, sans-serif;">${content}</div>`;
422
+ return html`<div style="${theme === 'dark' ? darkVars : lightVars} height: 720px; min-height: 720px; background: var(--bg); color: var(--text); overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Arial, sans-serif;">${content}</div>`;
420
423
  }
421
424
 
422
425
  export function fakeDocument(): TemplateResult {
423
426
  return html`
424
427
  <div class="fake-document">
425
428
  <div class="fake-title">Master Services Agreement</div>
426
- <div class="mono" style="font-size: 10px; color: hsl(0 0% 45%); margin-bottom: 24px;">Effective: May 2, 2026 · Acme Corp ↔ Lossless GmbH</div>
429
+ <div class="mono" style="font-size: 10px; color: hsl(0 0% 45%); margin-bottom: 24px;">Effective: May 2, 2026 · Acme Corp ↔ Example Company</div>
427
430
  ${Array.from({ length: 18 }).map((_, index) => html`<div class="fake-line ${index % 5 === 0 ? 'heavy' : ''} ${index % 4 === 3 ? 'short' : ''}"></div>`)}
428
431
  <div style="height: 16px;"></div>
429
432
  ${Array.from({ length: 8 }).map((_, index) => html`<div class="fake-line ${index % 3 === 2 ? 'short' : ''}"></div>`)}
430
433
  <div style="margin-top: 60px; font-size: 10px; font-weight: 600; color: hsl(0 0% 35%);">SIGNED ON BEHALF OF ACME CORP</div>
431
- <div style="margin-top: 70px; font-size: 10px; font-weight: 600; color: hsl(0 0% 35%);">SIGNED ON BEHALF OF LOSSLESS GMBH</div>
434
+ <div style="margin-top: 70px; font-size: 10px; font-weight: 600; color: hsl(0 0% 35%);">SIGNED ON BEHALF OF EXAMPLE COMPANY</div>
432
435
  </div>
433
436
  `;
434
437
  }
@@ -15,7 +15,7 @@ declare global {
15
15
 
16
16
  @customElement('sdig-workspace')
17
17
  export class SdigWorkspace extends DeesElement {
18
- public static demo = () => html`<sdig-workspace></sdig-workspace>`;
18
+ public static demo = () => html`<sdig-workspace theme="light" accent="#007aff"></sdig-workspace>`;
19
19
  public static demoGroups = ['Signature Digital Workspace'];
20
20
 
21
21
  @property({ type: String }) public accessor accent: string = '#3b82f6';
@@ -69,29 +69,29 @@ export class SdigWorkspace extends DeesElement {
69
69
  }
70
70
 
71
71
  :host([theme='light']) {
72
- --bg: hsl(0 0% 99%);
73
- --bg-el: hsl(0 0% 97%);
72
+ --bg: hsl(0 0% 100%);
73
+ --bg-el: hsl(240 9% 96.5%);
74
74
  --bg-card: hsl(0 0% 100%);
75
- --bg-input: hsl(0 0% 98%);
76
- --border: hsl(0 0% 90%);
77
- --border-subtle: hsl(0 0% 93%);
78
- --border-strong: hsl(0 0% 80%);
79
- --text: hsl(0 0% 9%);
80
- --text-sec: hsl(0 0% 32%);
81
- --text-muted: hsl(0 0% 45%);
82
- --text-dim: hsl(0 0% 62%);
83
- --hover: rgba(0,0,0,0.04);
84
- --hover-subtle: rgba(0,0,0,0.02);
85
- --row-hover: rgba(0,0,0,0.02);
86
- --success: #16a34a;
87
- --warning: #d97706;
88
- --error: #dc2626;
75
+ --bg-input: hsl(0 0% 100%);
76
+ --border: hsl(240 6% 89%);
77
+ --border-subtle: hsl(240 6% 92.5%);
78
+ --border-strong: hsl(240 6% 80%);
79
+ --text: hsl(240 6% 11%);
80
+ --text-sec: hsl(240 4% 34%);
81
+ --text-muted: hsl(240 3% 52%);
82
+ --text-dim: hsl(240 3% 66%);
83
+ --hover: rgba(0,0,0,0.05);
84
+ --hover-subtle: rgba(0,0,0,0.028);
85
+ --row-hover: rgba(0,0,0,0.028);
86
+ --success: #34c759;
87
+ --warning: #ff9500;
88
+ --error: #ff3b30;
89
89
  }
90
90
 
91
91
  * { box-sizing: border-box; }
92
92
  button { font: inherit; border: 0; cursor: pointer; }
93
93
  .workspace { display: flex; height: 100%; min-height: 720px; background: var(--bg); color: var(--text); overflow: hidden; }
94
- .sidebar { width: 220px; background: var(--bg); border-right: 1px solid var(--border-subtle); display: flex; flex-direction: column; flex-shrink: 0; height: 100%; }
94
+ .sidebar { width: 224px; background: color-mix(in srgb, var(--bg-el) 94%, transparent); border-right: 1px solid var(--border-subtle); display: flex; flex-direction: column; flex-shrink: 0; height: 100%; backdrop-filter: saturate(180%) blur(20px); }
95
95
  .brand { padding: 14px 16px 12px; display: flex; align-items: center; gap: 8px; }
96
96
  .logomark { width: 26px; height: 26px; border-radius: 6px; background: var(--bg-el); border: 1px solid var(--border-strong); display: inline-flex; align-items: center; justify-content: center; font-family: 'Plus Jakarta Sans', Inter, sans-serif; font-size: 13px; font-weight: 700; position: relative; }
97
97
  .logomark::after, .wordmark::after { content: ''; display: inline-block; border-radius: 50%; background: var(--accent); }
@@ -99,18 +99,18 @@ export class SdigWorkspace extends DeesElement {
99
99
  .wordmark { font-size: 13px; font-weight: 500; letter-spacing: -0.02em; white-space: nowrap; }
100
100
  .wordmark .dot { color: var(--text-muted); }
101
101
  .wordmark::after { width: 4px; height: 4px; margin-left: 3px; transform: translateY(-1px); }
102
- .workspace-card { margin: 0 12px 8px; padding: 7px 10px; background: var(--bg-el); border: 1px solid var(--border-subtle); border-radius: 6px; display: flex; align-items: center; gap: 8px; }
102
+ .workspace-card { margin: 0 12px 8px; padding: 7px 10px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 9px; display: flex; align-items: center; gap: 8px; }
103
103
  .workspace-badge { width: 18px; height: 18px; border-radius: 4px; background: linear-gradient(135deg, var(--accent), hsl(280 70% 60%)); color: white; font-size: 10px; font-weight: 700; display: flex; align-items: center; justify-content: center; }
104
104
  .workspace-name { font-size: 12px; font-weight: 500; line-height: 1.2; }
105
105
  .workspace-plan { font-size: 10px; color: var(--text-muted); }
106
106
  .nav-block { padding: 4px 0; }
107
- .nav-item { display: flex; align-items: center; gap: 10px; padding: 7px 10px; margin: 1px 8px; border-radius: 6px; color: var(--text-muted); background: transparent; transition: all 0.1s ease; font-size: 13px; position: relative; width: calc(100% - 16px); text-align: left; }
107
+ .nav-item { display: flex; align-items: center; gap: 9px; padding: 6px 9px; margin: 1px 9px; border-radius: 7px; color: var(--text-sec); background: transparent; transition: all 0.1s ease; font-size: 13px; position: relative; width: calc(100% - 18px); text-align: left; }
108
108
  .compact .nav-item { padding: 5px 10px; }
109
109
  .nav-item:hover { background: var(--hover-subtle); color: var(--text-sec); }
110
- .nav-item.active { background: var(--hover); color: var(--text); font-weight: 500; }
111
- .nav-item.active::before { content: ''; position: absolute; left: -8px; width: 2px; height: 14px; border-radius: 2px; background: var(--accent); }
110
+ .nav-item.active { background: var(--accent); color: white; font-weight: 510; box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 42%, transparent); }
111
+ .nav-item.active::before { display: none; }
112
112
  .nav-count { margin-left: auto; min-width: 18px; padding: 1px 6px; border-radius: 999px; background: var(--bg-el); color: var(--text-muted); font-size: 10px; text-align: center; }
113
- .github-card { margin: 8px 12px; padding: 10px; border: 1px solid var(--border-subtle); border-radius: 6px; background: var(--bg-el); }
113
+ .github-card { margin: 8px 12px; padding: 10px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-card); }
114
114
  .sparkline { margin-top: 8px; display: flex; gap: 2px; align-items: flex-end; height: 18px; }
115
115
  .sparkline span { flex: 1; background: var(--border-strong); border-radius: 1px; }
116
116
  .sparkline span:nth-last-child(-n+4) { background: var(--accent); }
@@ -151,12 +151,12 @@ export class SdigWorkspace extends DeesElement {
151
151
  return html`
152
152
  <aside class="sidebar">
153
153
  <div class="brand"><span class="logomark">s</span><span class="wordmark">signature<span class="dot">.</span>digital</span></div>
154
- <div class="workspace-card"><span class="workspace-badge">L</span><div style="flex: 1; min-width: 0;"><div class="workspace-name">Lossless GmbH</div><div class="workspace-plan">Cloud · Pro</div></div>${icon('chevronDown', 12)}</div>
154
+ <div class="workspace-card"><span class="workspace-badge">E</span><div style="flex: 1; min-width: 0;"><div class="workspace-name">Example workspace</div><div class="workspace-plan">Component preview</div></div></div>
155
155
  <div class="nav-block">${navItems.map((item) => this.navButton(item))}</div>
156
156
  <div style="flex: 1;"></div>
157
- <div class="github-card"><div style="display: flex; align-items: center; gap: 6px; margin-bottom: 8px; font-size: 11px; color: var(--text-sec); font-family: 'Intel One Mono', ui-monospace;">${icon('github', 13)} signature-digital/core</div><div style="display: flex; gap: 12px; font-size: 11px; color: var(--text-muted);"><span>${icon('star', 11)} 8.2k</span><span>${icon('git', 11)} 248</span></div><div class="sparkline">${[3, 5, 2, 7, 4, 6, 8, 5, 9, 6, 4, 8, 7, 10].map((height) => html`<span style="height: ${height * 10}%"></span>`)}</div></div>
157
+ <div class="github-card"><div style="display: flex; align-items: center; gap: 6px; margin-bottom: 6px; font-size: 11px; color: var(--text-sec); font-family: 'Intel One Mono', ui-monospace;">${icon('code', 13)} host controlled</div><div style="font-size: 10px; line-height: 1.45; color: var(--text-muted);">Demo data is replaceable through component properties and intent events.</div></div>
158
158
  <div class="nav-block" style="border-top: 1px solid var(--border-subtle); padding-top: 8px;">${lowerItems.map((item) => this.navButton(item))}</div>
159
- <div class="user-card"><span class="avatar">PK</span><div style="flex: 1; min-width: 0;"><div style="font-size: 12px; font-weight: 500;">Philipp K.</div><div style="font-family: 'Intel One Mono', ui-monospace; font-size: 10px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis;">philipp@lossless.com</div></div>${icon('more', 14)}</div>
159
+ <div class="user-card"><span class="avatar">DE</span><div style="flex: 1; min-width: 0;"><div style="font-size: 12px; font-weight: 500;">Demo owner</div><div style="font-family: 'Intel One Mono', ui-monospace; font-size: 10px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis;">owner@example.test</div></div>${icon('more', 14)}</div>
160
160
  </aside>
161
161
  `;
162
162
  }
@@ -177,6 +177,6 @@ export class SdigWorkspace extends DeesElement {
177
177
  }
178
178
 
179
179
  public render(): TemplateResult {
180
- return html`<div class="workspace ${this.density === 'compact' ? 'compact' : ''}" style="--accent: ${this.accent};" data-screen-label=${this.view}>${this.renderSidebar()}<main class="main">${this.renderView()}<div class="statusbar"><span style="display: inline-flex; align-items: center; gap: 5px;"><span style="width: 6px; height: 6px; border-radius: 50%; background: var(--success);"></span>api.signature.digital</span><span>eu-central-1</span><span>4 sigs queued</span><div style="flex: 1;"></div><span style="color: var(--accent);">Open Source · MIT</span><span>v0.42.1</span><span>${icon('git', 11)} main</span></div></main></div>`;
180
+ return html`<div class="workspace ${this.density === 'compact' ? 'compact' : ''}" style="--accent: ${this.accent};" data-screen-label=${this.view}>${this.renderSidebar()}<main class="main">${this.renderView()}<div class="statusbar"><span style="display: inline-flex; align-items: center; gap: 5px;"><span style="width: 6px; height: 6px; border-radius: 50%; background: var(--success);"></span>component preview</span><span>${this.documents.length} documents</span><div style="flex: 1;"></div><span style="color: var(--accent);">Open Source · MIT</span><span>host controlled</span></div></main></div>`;
181
181
  }
182
182
  }
package/ts_web/plugins.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  // third party
2
- import signaturePadMod from 'signature_pad';
3
- type signaturePadType = (typeof import('signature_pad'))['default'];
4
- const signaturePad = signaturePadMod as any as signaturePadType;
2
+ import SignaturePad from 'signature_pad';
3
+ export type { PointGroup as TSignaturePadPointGroup } from 'signature_pad';
5
4
 
6
5
  export {
7
- signaturePad,
6
+ SignaturePad as signaturePad,
8
7
  }
package/.smartconfig.json DELETED
@@ -1,82 +0,0 @@
1
- {
2
- "@git.zone/cli": {
3
- "projectType": "wcc",
4
- "module": {
5
- "githost": "gitlab.com",
6
- "gitscope": "signature.digital",
7
- "gitrepo": "catalog",
8
- "description": "A comprehensive catalog of customizable web components designed for building and managing e-signature applications.",
9
- "npmPackagename": "@signature.digital/catalog",
10
- "license": "MIT",
11
- "projectDomain": "signature.digital",
12
- "keywords": [
13
- "e-signature",
14
- "web components",
15
- "digital signature",
16
- "signature capture",
17
- "ECMAScript Modules",
18
- "typescript",
19
- "component library",
20
- "contract management",
21
- "frontend development",
22
- "signature pad",
23
- "custom elements",
24
- "electronic signing",
25
- "npm package"
26
- ]
27
- },
28
- "release": {
29
- "registries": [
30
- "https://verdaccio.lossless.digital",
31
- "https://registry.npmjs.org"
32
- ],
33
- "accessLevel": "public"
34
- }
35
- },
36
- "@git.zone/tsbundle": {
37
- "bundles": [
38
- {
39
- "from": "./html/index.ts",
40
- "to": "./dist_bundle/bundle.js",
41
- "outputMode": "bundle",
42
- "bundler": "esbuild",
43
- "production": true,
44
- "includeFiles": [
45
- "./html/index.html"
46
- ]
47
- }
48
- ]
49
- },
50
- "@git.zone/tswatch": {
51
- "server": {
52
- "enabled": true,
53
- "port": 3002,
54
- "serveDir": "./dist_watch/",
55
- "liveReload": true
56
- },
57
- "bundles": [
58
- {
59
- "name": "element-bundle",
60
- "from": "./html/index.ts",
61
- "to": "./dist_watch/bundle.js",
62
- "watchPatterns": [
63
- "./ts_web/**/*",
64
- "./html/index.ts"
65
- ],
66
- "triggerReload": true,
67
- "bundler": "esbuild",
68
- "production": false
69
- },
70
- {
71
- "name": "html",
72
- "from": "./html/index.html",
73
- "to": "./dist_watch/index.html",
74
- "watchPatterns": [
75
- "./html/**/*"
76
- ],
77
- "triggerReload": true
78
- }
79
- ]
80
- },
81
- "@ship.zone/szci": {}
82
- }