@thalassic/themes 22.14.2 → 22.15.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": "@thalassic/themes",
3
- "version": "22.14.2",
3
+ "version": "22.15.0",
4
4
  "license": "MIT",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^22.0.0",
@@ -0,0 +1,5 @@
1
+ @use '../../mixins' as mixins;
2
+
3
+ .tls-activity-heatmap {
4
+ @include mixins.color-variants('tls-activity-heatmap');
5
+ }
@@ -0,0 +1,16 @@
1
+ .tls-activity-heatmap {
2
+ &.tls-activity-heatmap--sm {
3
+ --tls-activity-heatmap-cell-size: 10px;
4
+ --tls-activity-heatmap-font-size: var(--font-label-small-size);
5
+ }
6
+
7
+ &.tls-activity-heatmap--md {
8
+ --tls-activity-heatmap-cell-size: 14px;
9
+ --tls-activity-heatmap-font-size: var(--font-label-small-size);
10
+ }
11
+
12
+ &.tls-activity-heatmap--lg {
13
+ --tls-activity-heatmap-cell-size: 18px;
14
+ --tls-activity-heatmap-font-size: var(--font-label-medium-size);
15
+ }
16
+ }
@@ -0,0 +1,150 @@
1
+ @use '../../mixins' as mixins;
2
+ @use '../../functions' as functions;
3
+
4
+ .tls-activity-heatmap {
5
+ // Fill of a day with no activity, and the base every shaded cell is mixed against.
6
+ --tls-activity-heatmap-empty: var(--color-surface-container-high);
7
+ // Hairline that keeps a faint cell readable against the surface behind it.
8
+ --tls-activity-heatmap-outline: #{functions.tint(var(--color-on-surface), 12%)};
9
+ // Gap between cells, shared by the grid and the labels aligned to it.
10
+ --tls-activity-heatmap-gap: var(--spacing-1);
11
+
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: var(--spacing-2);
15
+
16
+ &__viewport {
17
+ // A year of weeks rarely fits a narrow container; scroll rather than shrink the cells.
18
+ overflow-x: auto;
19
+ }
20
+
21
+ &__chart {
22
+ width: max-content;
23
+
24
+ display: grid;
25
+ grid-template-columns: auto auto;
26
+ gap: var(--tls-activity-heatmap-gap);
27
+ }
28
+
29
+ &__months {
30
+ grid-column: 2;
31
+
32
+ display: grid;
33
+ grid-template-columns: repeat(
34
+ var(--tls-activity-heatmap-weeks, 0),
35
+ var(--tls-activity-heatmap-cell-size)
36
+ );
37
+ column-gap: var(--tls-activity-heatmap-gap);
38
+ }
39
+
40
+ &__month {
41
+ font-size: var(--tls-activity-heatmap-font-size);
42
+ line-height: 1;
43
+ color: var(--color-on-surface-variant);
44
+ }
45
+
46
+ &__weekdays {
47
+ grid-column: 1;
48
+
49
+ display: grid;
50
+ grid-auto-rows: var(--tls-activity-heatmap-cell-size);
51
+ align-items: center;
52
+ row-gap: var(--tls-activity-heatmap-gap);
53
+ }
54
+
55
+ &__weekday {
56
+ font-size: var(--tls-activity-heatmap-font-size);
57
+ line-height: 1;
58
+ color: var(--color-on-surface-variant);
59
+ }
60
+
61
+ &__grid {
62
+ grid-column: 2;
63
+
64
+ display: grid;
65
+ grid-auto-rows: var(--tls-activity-heatmap-cell-size);
66
+ row-gap: var(--tls-activity-heatmap-gap);
67
+ }
68
+
69
+ &__row {
70
+ display: grid;
71
+ grid-template-columns: repeat(
72
+ var(--tls-activity-heatmap-weeks, 0),
73
+ var(--tls-activity-heatmap-cell-size)
74
+ );
75
+ column-gap: var(--tls-activity-heatmap-gap);
76
+ }
77
+
78
+ &__day {
79
+ position: relative;
80
+
81
+ height: var(--tls-activity-heatmap-cell-size);
82
+
83
+ border: 1px solid var(--tls-activity-heatmap-outline);
84
+ border-radius: var(--radius-sm);
85
+
86
+ // The fill reads as a share of the theme color laid over the empty surface, so any
87
+ // level count maps onto one continuous scale.
88
+ background-color: color-mix(
89
+ in oklab,
90
+ var(--tls-activity-heatmap-color) calc(var(--tls-activity-heatmap-intensity, 0) * 100%),
91
+ var(--tls-activity-heatmap-empty)
92
+ );
93
+
94
+ cursor: pointer;
95
+
96
+ @include mixins.motion(essential) {
97
+ transition: border-color var(--motion-fast) var(--motion-ease-in-out);
98
+ }
99
+
100
+ &:hover {
101
+ border-color: var(--color-on-surface);
102
+ }
103
+
104
+ &:focus-visible {
105
+ // The ring overflows onto the neighbouring cells; lift the focused one above them.
106
+ z-index: 1;
107
+
108
+ @include mixins.focus-ring;
109
+ }
110
+
111
+ // Padding days only complete the first and last week, so they leave no visual trace.
112
+ &--outside {
113
+ border-color: transparent;
114
+
115
+ background-color: transparent;
116
+
117
+ cursor: default;
118
+ }
119
+
120
+ &--today {
121
+ border-color: var(--color-on-surface);
122
+ }
123
+ }
124
+
125
+ &__legend {
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: flex-end;
129
+ gap: var(--tls-activity-heatmap-gap);
130
+ }
131
+
132
+ &__legend-label {
133
+ font-size: var(--tls-activity-heatmap-font-size);
134
+ color: var(--color-on-surface-variant);
135
+ }
136
+
137
+ &__legend-swatch {
138
+ width: var(--tls-activity-heatmap-cell-size);
139
+ height: var(--tls-activity-heatmap-cell-size);
140
+
141
+ border: 1px solid var(--tls-activity-heatmap-outline);
142
+ border-radius: var(--radius-sm);
143
+
144
+ background-color: color-mix(
145
+ in oklab,
146
+ var(--tls-activity-heatmap-color) calc(var(--tls-activity-heatmap-intensity, 0) * 100%),
147
+ var(--tls-activity-heatmap-empty)
148
+ );
149
+ }
150
+ }
@@ -0,0 +1,3 @@
1
+ @forward 'activity-heatmap';
2
+ @forward 'activity-heatmap-color';
3
+ @forward 'activity-heatmap-size';
@@ -1,3 +1,4 @@
1
+ @forward 'activity-heatmap';
1
2
  @forward 'alert';
2
3
  @forward 'autocomplete';
3
4
  @forward 'badge';
@@ -41,6 +42,7 @@
41
42
  @forward 'pin-input';
42
43
  @forward 'popover';
43
44
  @forward 'radio-button';
45
+ @forward 'rich-text-editor';
44
46
  @forward 'skeleton';
45
47
  @forward 'splitter';
46
48
  @forward 'table';
@@ -0,0 +1,3 @@
1
+ @forward 'rich-text-editor';
2
+ @forward 'rich-text-editor-content';
3
+ @forward 'rich-text-editor-size';
@@ -0,0 +1,115 @@
1
+ // The editable document surface managed by ProseMirror: the textbox itself (sizing,
2
+ // padding, placeholder) and the typography of the rich-text elements inside it.
3
+ .tls-rich-text-editor__content {
4
+ position: relative;
5
+
6
+ min-height: calc(var(--tls-rich-text-editor-min-rows, 4) * 1.6em);
7
+
8
+ padding: var(--tls-rich-text-editor-padding-block) var(--tls-rich-text-editor-padding-inline);
9
+
10
+ outline: none;
11
+
12
+ color: var(--color-on-surface);
13
+
14
+ font-family: inherit;
15
+ overflow-wrap: break-word;
16
+
17
+ &[data-empty][data-placeholder]::before {
18
+ content: attr(data-placeholder);
19
+
20
+ position: absolute;
21
+ inset-block-start: var(--tls-rich-text-editor-padding-block);
22
+ inset-inline-start: var(--tls-rich-text-editor-padding-inline);
23
+
24
+ color: var(--color-outline);
25
+
26
+ pointer-events: none;
27
+ }
28
+
29
+ > :first-child {
30
+ margin-block-start: 0;
31
+ }
32
+
33
+ > :last-child {
34
+ margin-block-end: 0;
35
+ }
36
+
37
+ p,
38
+ ul,
39
+ ol,
40
+ blockquote,
41
+ pre {
42
+ margin-block: var(--spacing-2);
43
+ }
44
+
45
+ h1,
46
+ h2,
47
+ h3 {
48
+ margin-block: var(--spacing-3) var(--spacing-2);
49
+
50
+ font-weight: 600;
51
+ line-height: 1.25;
52
+ }
53
+
54
+ h1 {
55
+ font-size: 1.5em;
56
+ }
57
+
58
+ h2 {
59
+ font-size: 1.3em;
60
+ }
61
+
62
+ h3 {
63
+ font-size: 1.15em;
64
+ }
65
+
66
+ ul,
67
+ ol {
68
+ padding-inline-start: var(--spacing-6);
69
+ }
70
+
71
+ li {
72
+ margin-block: var(--spacing-1);
73
+ }
74
+
75
+ a {
76
+ color: var(--color-primary);
77
+ text-decoration: underline;
78
+ }
79
+
80
+ blockquote {
81
+ padding-inline-start: var(--spacing-3);
82
+
83
+ border-inline-start: 2px solid var(--color-outline-variant);
84
+
85
+ color: var(--color-on-surface-variant);
86
+ }
87
+
88
+ code {
89
+ padding: 0 var(--spacing-1);
90
+
91
+ border-radius: var(--radius-sm);
92
+
93
+ background-color: var(--color-surface-container-high);
94
+
95
+ font-family: monospace;
96
+ font-size: 0.9em;
97
+ }
98
+
99
+ pre {
100
+ padding: var(--spacing-2) var(--spacing-3);
101
+
102
+ border-radius: var(--radius-md);
103
+
104
+ background-color: var(--color-surface-container-high);
105
+
106
+ font-family: monospace;
107
+ white-space: pre-wrap;
108
+
109
+ code {
110
+ padding: 0;
111
+
112
+ background-color: transparent;
113
+ }
114
+ }
115
+ }
@@ -0,0 +1,22 @@
1
+ .tls-rich-text-editor {
2
+ --tls-rich-text-editor-padding-inline: var(--spacing-3);
3
+
4
+ // Toolbar controls and the link-bar actions keep a fixed box across every control
5
+ // size, so the toolbar's rhythm stays stable while the editable area scales.
6
+ --tls-rich-text-editor-button-size: 32px;
7
+
8
+ // Typography comes from the shared form-control size classes
9
+ // (`form-control/_form-control-size.scss`), which the component emits on its
10
+ // host; only the editable area's block padding is size-specific here.
11
+ &.tls-form-control--sm {
12
+ --tls-rich-text-editor-padding-block: var(--spacing-1);
13
+ }
14
+
15
+ &.tls-form-control--md {
16
+ --tls-rich-text-editor-padding-block: var(--spacing-2);
17
+ }
18
+
19
+ &.tls-form-control--lg {
20
+ --tls-rich-text-editor-padding-block: var(--spacing-3);
21
+ }
22
+ }
@@ -0,0 +1,167 @@
1
+ @use '../../mixins' as mixins;
2
+
3
+ .tls-rich-text-editor {
4
+ &.tls-form-control {
5
+ padding-inline: 0;
6
+
7
+ overflow: hidden;
8
+
9
+ &:not(.tls-form-control--disabled):not(.tls-form-control--show-error):hover {
10
+ --tls-form-control-border-color: var(--color-outline-variant);
11
+ }
12
+ }
13
+
14
+ &__toolbar {
15
+ padding: var(--spacing-1);
16
+
17
+ border-block-end: var(--tls-form-control-border-width, 1px) solid var(--color-outline-variant);
18
+
19
+ background-color: var(--color-surface-container-low);
20
+ }
21
+
22
+ &__separator {
23
+ background-color: var(--color-outline-variant);
24
+ }
25
+
26
+ &__button {
27
+ // The transparent border reserves the box the active state paints into, so
28
+ // turning a control on never shifts the toolbar's metrics.
29
+ border: 1px solid transparent;
30
+ border-radius: var(--radius-sm);
31
+
32
+ background-color: transparent;
33
+
34
+ color: var(--color-on-surface-variant);
35
+
36
+ @include mixins.motion(essential) {
37
+ transition:
38
+ color var(--motion-fast) var(--motion-ease-in-out),
39
+ border-color var(--motion-fast) var(--motion-ease-in-out),
40
+ background-color var(--motion-fast) var(--motion-ease-in-out);
41
+ }
42
+
43
+ @include mixins.touch-target(var(--tls-rich-text-editor-button-size));
44
+
45
+ // The neutral hover excludes the active control so its pressed tint stays
46
+ // readable under the cursor; the active control hovers within its own hue below.
47
+ &:not(:disabled):hover:not(.tls-rich-text-editor__button--active) {
48
+ background-color: var(--color-surface-container-highest);
49
+
50
+ color: var(--color-on-surface);
51
+ }
52
+
53
+ &:not(:disabled):active {
54
+ background-color: var(--color-surface-container-high);
55
+ }
56
+
57
+ &:focus-visible {
58
+ @include mixins.focus-ring;
59
+ }
60
+
61
+ &--active {
62
+ border-color: var(--color-primary);
63
+
64
+ background-color: var(--color-primary-container);
65
+
66
+ // The container's paired on-color, not `--color-primary`: the heading controls
67
+ // render text glyphs rather than icons, so this pairing has to clear the 4.5:1
68
+ // text threshold, not the 3:1 one that would suffice for an icon.
69
+ color: var(--color-on-primary-container);
70
+
71
+ &:not(:disabled):hover {
72
+ background-color: color-mix(
73
+ in srgb,
74
+ var(--color-primary-container) 85%,
75
+ var(--color-surface)
76
+ );
77
+ }
78
+
79
+ &:not(:disabled):active {
80
+ background-color: color-mix(
81
+ in srgb,
82
+ var(--color-primary-container) 70%,
83
+ var(--color-surface)
84
+ );
85
+ }
86
+ }
87
+
88
+ &:disabled {
89
+ color: var(--color-outline);
90
+ }
91
+ }
92
+
93
+ &__link-bar {
94
+ padding: var(--spacing-2);
95
+
96
+ border-block-start: var(--tls-form-control-border-width, 1px) solid var(--color-outline-variant);
97
+
98
+ background-color: var(--color-surface-container-low);
99
+ }
100
+
101
+ &__link-input {
102
+ padding: var(--spacing-1) var(--spacing-2);
103
+
104
+ border: 1px solid var(--color-outline-variant);
105
+ border-radius: var(--radius-sm);
106
+
107
+ background-color: var(--color-surface-container-lowest);
108
+
109
+ color: var(--color-on-surface);
110
+
111
+ &:focus-visible {
112
+ outline: none;
113
+
114
+ border-color: var(--color-primary);
115
+ }
116
+ }
117
+
118
+ &__link-action {
119
+ height: var(--tls-rich-text-editor-button-size);
120
+
121
+ padding-inline: var(--spacing-3);
122
+
123
+ display: inline-flex;
124
+ align-items: center;
125
+
126
+ border: none;
127
+ border-radius: var(--radius-sm);
128
+
129
+ background-color: var(--color-primary);
130
+
131
+ color: var(--color-on-primary);
132
+
133
+ cursor: pointer;
134
+
135
+ @include mixins.motion(essential) {
136
+ transition: background-color var(--motion-fast) var(--motion-ease-in-out);
137
+ }
138
+
139
+ @include mixins.touch-target(var(--tls-rich-text-editor-button-size));
140
+
141
+ &:hover {
142
+ background-color: color-mix(in srgb, var(--color-primary) 90%, var(--color-on-primary));
143
+ }
144
+
145
+ &:active {
146
+ background-color: color-mix(in srgb, var(--color-primary) 80%, var(--color-on-primary));
147
+ }
148
+
149
+ &:focus-visible {
150
+ @include mixins.focus-ring;
151
+ }
152
+
153
+ &--ghost {
154
+ background-color: transparent;
155
+
156
+ color: var(--color-on-surface-variant);
157
+
158
+ &:hover {
159
+ background-color: var(--color-surface-container-highest);
160
+ }
161
+
162
+ &:active {
163
+ background-color: var(--color-surface-container-high);
164
+ }
165
+ }
166
+ }
167
+ }
@@ -78,6 +78,15 @@
78
78
  transition: color var(--motion-fast),
79
79
  background-color var(--motion-fast);
80
80
 
81
+ // The header is a tablist: it resolves the clicked step from
82
+ // `event.target` and ignores any target that is not an `HTMLElement`,
83
+ // so a click landing on an SVG child (a consumer-supplied step icon)
84
+ // never selects the step. Making SVG content transparent to pointer
85
+ // events keeps the control itself the target.
86
+ svg {
87
+ pointer-events: none;
88
+ }
89
+
81
90
  &__index {
82
91
  width: var(--tls-stepper-index-size);
83
92
  height: var(--tls-stepper-index-size);
@@ -87,6 +87,16 @@
87
87
 
88
88
  transition: background-color var(--motion-fast);
89
89
 
90
+ // The tablist resolves the clicked tab from `event.target` and ignores
91
+ // any target that is not an `HTMLElement`, so a click landing on an SVG
92
+ // child (an icon rendered into the tab label) never selects the tab.
93
+ // Making SVG content transparent to pointer events keeps the control
94
+ // itself the target. Targeted by element name deliberately: the content
95
+ // is consumer-provided, so no class is available to hook.
96
+ svg {
97
+ pointer-events: none;
98
+ }
99
+
90
100
  // Focus is distinct from selection here: the strip is a roving-tabindex
91
101
  // widget, so arrowing moves focus onto tabs that are not selected and
92
102
  // the active-indicator color alone cannot stand in for a focus