canny-ui 2.0.0 → 4.0.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.
@@ -0,0 +1,129 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // List + ListItem — vertical row layout (participants, message lists, settings).
4
+
5
+ .cny-list {
6
+ list-style: none;
7
+ margin: 0;
8
+ padding: 0;
9
+ display: flex;
10
+ flex-direction: column;
11
+
12
+ &.bordered {
13
+ border: 1px solid var(--border-color);
14
+ border-radius: var(--radius-sm);
15
+ overflow: hidden;
16
+ background: var(--bg-surface-lowest);
17
+ }
18
+ &.dividers .cny-list-item:not(:last-child),
19
+ &.dividers > .cny-list-item-wrap:not(:last-child) {
20
+ border-bottom: 1px solid var(--hairline-color);
21
+ }
22
+ &.bordered.dividers .cny-list-item:not(:last-child),
23
+ &.bordered.dividers > .cny-list-item-wrap:not(:last-child) {
24
+ border-bottom: 1px solid var(--hairline-color);
25
+ }
26
+ }
27
+
28
+ .cny-list-item-wrap {
29
+ display: flex;
30
+ }
31
+
32
+ .cny-list-item {
33
+ display: flex;
34
+ align-items: center;
35
+ gap: 12px;
36
+ width: 100%;
37
+ padding: 12px 14px;
38
+ background: transparent;
39
+ color: var(--text-primary);
40
+ text-decoration: none;
41
+ border: 0;
42
+ font-family: var(--font-body);
43
+ font-size: 0.875rem;
44
+ text-align: left;
45
+ transition: background-color 140ms ease, color 140ms ease;
46
+
47
+ // Sizes
48
+ .cny-list.size-sm & { padding: 8px 12px; font-size: 0.8125rem; gap: 10px; }
49
+ .cny-list.size-lg & { padding: 16px 18px; font-size: 0.9375rem; gap: 14px; }
50
+
51
+ &-leading {
52
+ flex: none;
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ color: var(--text-muted);
57
+ }
58
+ &-body {
59
+ flex: 1 1 auto;
60
+ min-width: 0;
61
+ display: flex;
62
+ flex-direction: column;
63
+ gap: 2px;
64
+ }
65
+ &-primary {
66
+ font-weight: 550;
67
+ line-height: 1.35;
68
+ color: var(--text-primary);
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ }
73
+ &-secondary {
74
+ font-size: 0.8125rem;
75
+ line-height: 1.4;
76
+ color: var(--text-muted);
77
+ overflow: hidden;
78
+ text-overflow: ellipsis;
79
+ white-space: nowrap;
80
+ }
81
+ &-trailing {
82
+ flex: none;
83
+ display: inline-flex;
84
+ align-items: center;
85
+ color: var(--text-muted);
86
+ }
87
+
88
+ // Interactive (button or link)
89
+ &.is-interactive {
90
+ cursor: pointer;
91
+ &:hover {
92
+ background: var(--bg-surface-low);
93
+ color: var(--text-primary);
94
+ }
95
+ &:focus-visible {
96
+ outline: 2px solid var(--border-focus);
97
+ outline-offset: -2px;
98
+ }
99
+ }
100
+
101
+ &.is-active {
102
+ background: color-mix(in srgb, var(--color-primary) 10%, var(--bg-surface-low));
103
+ color: var(--color-primary);
104
+
105
+ .cny-list-item-leading,
106
+ .cny-list-item-trailing { color: var(--color-primary); }
107
+ .cny-list-item-primary { color: var(--color-primary); font-weight: 600; }
108
+ }
109
+
110
+ &.is-disabled {
111
+ opacity: 0.55;
112
+ pointer-events: none;
113
+ }
114
+ }
115
+
116
+ .cny-list-separator {
117
+ height: 1px;
118
+ background: var(--hairline-color);
119
+ margin: 4px 0;
120
+ }
121
+
122
+ .cny-list-subheader {
123
+ padding: 10px 14px 6px;
124
+ font-size: 0.6875rem;
125
+ font-weight: 650;
126
+ letter-spacing: 0.08em;
127
+ text-transform: uppercase;
128
+ color: var(--text-muted);
129
+ }
@@ -0,0 +1,115 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Menu (DropdownMenu) — popup menu with items, checkboxes, radios, submenus.
4
+
5
+ @keyframes cny-menu-in {
6
+ from { opacity: 0; transform: translateY(-4px) scale(0.97); }
7
+ to { opacity: 1; transform: translateY(0) scale(1); }
8
+ }
9
+
10
+ .cny-menu-content {
11
+ z-index: 1010;
12
+ display: flex;
13
+ flex-direction: column;
14
+ gap: 1px;
15
+ min-width: 180px;
16
+ padding: 4px;
17
+ background: var(--bg-surface-lowest);
18
+ border: 1px solid var(--border-color);
19
+ border-radius: var(--radius-sm);
20
+ box-shadow:
21
+ 0 1px 0 rgba(15, 23, 42, 0.04),
22
+ 0 8px 24px -8px rgba(15, 23, 42, 0.2);
23
+ font-family: var(--font-body);
24
+ outline: none;
25
+ animation: cny-menu-in 140ms cubic-bezier(0.2, 0.8, 0.2, 1);
26
+
27
+ &.size-sm { min-width: 140px; padding: 3px; }
28
+
29
+ &[data-side='top'] { transform-origin: bottom; }
30
+ &[data-side='bottom'] { transform-origin: top; }
31
+ &[data-side='left'] { transform-origin: right; }
32
+ &[data-side='right'] { transform-origin: left; }
33
+ }
34
+
35
+ .cny-menu-item {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 10px;
39
+ padding: 7px 10px;
40
+ font-size: 0.875rem;
41
+ color: var(--text-primary);
42
+ border-radius: var(--radius-xs);
43
+ cursor: pointer;
44
+ outline: none;
45
+ user-select: none;
46
+ position: relative;
47
+ white-space: nowrap;
48
+
49
+ .cny-menu-content.size-sm & { padding: 6px 8px; font-size: 0.8125rem; }
50
+
51
+ &-icon {
52
+ flex: none;
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ width: 16px;
57
+ height: 16px;
58
+ color: var(--text-muted);
59
+ }
60
+ &-label { flex: 1 1 auto; }
61
+ &-shortcut {
62
+ flex: none;
63
+ margin-left: 16px;
64
+ font-family: var(--font-mono);
65
+ font-size: 0.6875rem;
66
+ color: var(--text-muted);
67
+ letter-spacing: 0.02em;
68
+ }
69
+ &-chevron {
70
+ flex: none;
71
+ display: inline-flex;
72
+ color: var(--text-muted);
73
+ }
74
+
75
+ &[data-highlighted] {
76
+ background: color-mix(in srgb, var(--color-primary) 10%, var(--bg-surface-low));
77
+ color: var(--text-primary);
78
+ }
79
+ &[data-highlighted] .cny-menu-item-icon,
80
+ &[data-highlighted] .cny-menu-item-chevron { color: var(--color-primary); }
81
+
82
+ &[data-disabled] {
83
+ color: var(--text-disabled);
84
+ cursor: not-allowed;
85
+ pointer-events: none;
86
+ }
87
+
88
+ &.is-destructive {
89
+ color: var(--color-danger);
90
+ .cny-menu-item-icon { color: var(--color-danger); }
91
+ &[data-highlighted] {
92
+ background: color-mix(in srgb, var(--color-danger) 10%, var(--bg-surface-low));
93
+ color: var(--color-danger);
94
+ }
95
+ }
96
+ }
97
+
98
+ .cny-menu-label {
99
+ padding: 8px 10px 4px;
100
+ font-size: 0.6875rem;
101
+ font-weight: 650;
102
+ letter-spacing: 0.08em;
103
+ text-transform: uppercase;
104
+ color: var(--text-muted);
105
+ }
106
+
107
+ .cny-menu-separator {
108
+ height: 1px;
109
+ background: var(--hairline-color);
110
+ margin: 4px -1px;
111
+ }
112
+
113
+ @media (prefers-reduced-motion: reduce) {
114
+ .cny-menu-content { animation: none; }
115
+ }
@@ -0,0 +1,62 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Pagination — flat numbered nav with prev/next chevrons.
4
+
5
+ .cny-pagination {
6
+ display: inline-flex;
7
+ align-items: center;
8
+ gap: 4px;
9
+ font-family: var(--font-body);
10
+
11
+ &-btn {
12
+ min-width: 32px;
13
+ height: 32px;
14
+ padding: 0 8px;
15
+ display: inline-flex;
16
+ align-items: center;
17
+ justify-content: center;
18
+ background: transparent;
19
+ color: var(--text-secondary);
20
+ border: 1px solid transparent;
21
+ border-radius: var(--radius-sm);
22
+ font-size: 0.8125rem;
23
+ font-weight: 500;
24
+ cursor: pointer;
25
+ transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
26
+
27
+ &:hover:not(:disabled):not(.is-active) {
28
+ background: var(--bg-surface-low);
29
+ color: var(--text-primary);
30
+ }
31
+ &:focus-visible {
32
+ outline: 2px solid var(--color-primary);
33
+ outline-offset: 1px;
34
+ }
35
+ &:disabled {
36
+ opacity: 0.4;
37
+ cursor: not-allowed;
38
+ }
39
+ &.is-active {
40
+ background: var(--color-primary);
41
+ color: var(--color-primary-on);
42
+ border-color: var(--color-primary);
43
+ }
44
+ }
45
+
46
+ &-control { color: var(--text-muted); }
47
+
48
+ &-ellipsis {
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ min-width: 24px;
53
+ color: var(--text-muted);
54
+ }
55
+
56
+ &-sm {
57
+ .cny-pagination-btn { min-width: 28px; height: 28px; font-size: 0.75rem; padding: 0 6px; }
58
+ }
59
+ &-lg {
60
+ .cny-pagination-btn { min-width: 36px; height: 36px; font-size: 0.875rem; padding: 0 10px; }
61
+ }
62
+ }
@@ -0,0 +1,63 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // PanelGroup — resizable split panels. Percentage-based, so it fills any container responsively.
4
+
5
+ .cny-panel-group {
6
+ display: flex;
7
+ flex-direction: row;
8
+ width: 100%;
9
+ height: 100%;
10
+ overflow: hidden;
11
+
12
+ &.is-vertical {
13
+ flex-direction: column;
14
+ }
15
+ }
16
+
17
+ .cny-panel {
18
+ position: relative;
19
+ min-width: 0;
20
+ min-height: 0;
21
+ overflow: auto;
22
+ }
23
+
24
+ .cny-panel-handle {
25
+ position: relative;
26
+ flex: none;
27
+ align-self: stretch;
28
+ background: var(--hairline-color);
29
+ transition: background-color 120ms ease;
30
+ touch-action: none;
31
+ z-index: 1;
32
+
33
+ // generous invisible hit area around the thin visible line
34
+ &::before {
35
+ content: '';
36
+ position: absolute;
37
+ inset: -4px;
38
+ }
39
+
40
+ &:hover,
41
+ &:focus-visible {
42
+ background: var(--color-primary);
43
+ outline: none;
44
+ }
45
+
46
+ &-h {
47
+ width: 5px;
48
+ cursor: col-resize;
49
+ }
50
+
51
+ &-v {
52
+ height: 5px;
53
+ cursor: row-resize;
54
+ }
55
+
56
+ &[aria-disabled='true'] {
57
+ cursor: default;
58
+
59
+ &:hover {
60
+ background: var(--hairline-color);
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,39 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Popover — generic floating surface for inline forms, filters, info.
4
+
5
+ @keyframes cny-popover-in {
6
+ from { opacity: 0; transform: translateY(-4px) scale(0.97); }
7
+ to { opacity: 1; transform: translateY(0) scale(1); }
8
+ }
9
+
10
+ .cny-popover-content {
11
+ z-index: 1010;
12
+ padding: 14px;
13
+ background: var(--bg-surface-lowest);
14
+ border: 1px solid var(--border-color);
15
+ border-radius: var(--radius-sm);
16
+ box-shadow:
17
+ 0 1px 0 rgba(15, 23, 42, 0.04),
18
+ 0 12px 28px -12px rgba(15, 23, 42, 0.22);
19
+ font-family: var(--font-body);
20
+ color: var(--text-primary);
21
+ outline: none;
22
+ animation: cny-popover-in 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
23
+ max-width: calc(100vw - 16px);
24
+
25
+ &[data-side='top'] { transform-origin: bottom; }
26
+ &[data-side='bottom'] { transform-origin: top; }
27
+ &[data-side='left'] { transform-origin: right; }
28
+ &[data-side='right'] { transform-origin: left; }
29
+ }
30
+
31
+ .cny-popover-arrow {
32
+ fill: var(--bg-surface-lowest);
33
+ stroke: var(--border-color);
34
+ stroke-width: 1px;
35
+ }
36
+
37
+ @media (prefers-reduced-motion: reduce) {
38
+ .cny-popover-content { animation: none; }
39
+ }
@@ -0,0 +1,95 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Slider — flat track + filled range + circular thumb.
4
+
5
+ .cny-slider {
6
+ --slider-accent: var(--color-primary);
7
+
8
+ position: relative;
9
+ display: flex;
10
+ align-items: center;
11
+ user-select: none;
12
+ touch-action: none;
13
+ width: 100%;
14
+ height: 20px;
15
+
16
+ &-track {
17
+ position: relative;
18
+ flex: 1;
19
+ background: var(--bg-surface-low);
20
+ border-radius: 999px;
21
+ height: 4px;
22
+ overflow: hidden;
23
+ }
24
+
25
+ &-range {
26
+ position: absolute;
27
+ background: var(--slider-accent);
28
+ border-radius: 999px;
29
+ height: 100%;
30
+ }
31
+
32
+ &-thumb {
33
+ display: block;
34
+ width: 16px;
35
+ height: 16px;
36
+ background: var(--bg-surface-lowest);
37
+ border: 2px solid var(--slider-accent);
38
+ border-radius: 50%;
39
+ cursor: grab;
40
+ transition: transform 120ms ease, box-shadow 120ms ease;
41
+
42
+ &:hover { transform: scale(1.08); }
43
+ &:active { cursor: grabbing; }
44
+ &:focus-visible {
45
+ outline: 2px solid var(--slider-accent);
46
+ outline-offset: 2px;
47
+ }
48
+ }
49
+
50
+ &-bubble {
51
+ position: absolute;
52
+ bottom: calc(100% + 6px);
53
+ left: 50%;
54
+ transform: translateX(-50%);
55
+ background: var(--text-primary);
56
+ color: var(--bg-surface-lowest);
57
+ font-size: 11px;
58
+ font-weight: 500;
59
+ padding: 2px 6px;
60
+ border-radius: var(--radius-sm);
61
+ white-space: nowrap;
62
+ pointer-events: none;
63
+ opacity: 0;
64
+ transition: opacity 120ms ease;
65
+ }
66
+
67
+ &-thumb:hover &-bubble,
68
+ &-thumb:focus-visible &-bubble,
69
+ &-thumb[data-state='active'] &-bubble { opacity: 1; }
70
+
71
+ &[data-disabled] {
72
+ opacity: 0.5;
73
+ .cny-slider-thumb { cursor: not-allowed; }
74
+ }
75
+
76
+ // Sizes
77
+ &-sm { height: 16px; .cny-slider-track { height: 3px; } .cny-slider-thumb { width: 12px; height: 12px; } }
78
+ &-lg { height: 24px; .cny-slider-track { height: 6px; } .cny-slider-thumb { width: 20px; height: 20px; } }
79
+
80
+ // Colors
81
+ &-success { --slider-accent: var(--color-success); }
82
+ &-warning { --slider-accent: var(--color-warning); }
83
+ &-danger { --slider-accent: var(--color-danger); }
84
+
85
+ // Vertical orientation
86
+ &[data-orientation='vertical'] {
87
+ flex-direction: column;
88
+ width: 20px;
89
+ height: 100%;
90
+ min-height: 120px;
91
+
92
+ .cny-slider-track { width: 4px; height: 100%; flex: 1; }
93
+ .cny-slider-range { width: 100%; height: auto; }
94
+ }
95
+ }
@@ -0,0 +1,125 @@
1
+ @use '../tokens/primitives' as *;
2
+
3
+ // Stepper — wizard / multi-step progress trail.
4
+
5
+ .cny-stepper {
6
+ list-style: none;
7
+ margin: 0;
8
+ padding: 0;
9
+ font-family: var(--font-body);
10
+
11
+ &-step {
12
+ display: flex;
13
+ align-items: center;
14
+ min-width: 0;
15
+ }
16
+
17
+ &-step-row {
18
+ display: flex;
19
+ align-items: center;
20
+ gap: $space-2;
21
+ padding: 0;
22
+ background: transparent;
23
+ border: 0;
24
+ color: inherit;
25
+ text-align: left;
26
+ cursor: default;
27
+ border-radius: var(--radius-sm);
28
+ min-width: 0;
29
+
30
+ &:not(:disabled) {
31
+ cursor: pointer;
32
+ &:hover .cny-stepper-label { color: var(--text-primary); }
33
+ }
34
+ &:focus-visible {
35
+ outline: 2px solid var(--color-primary);
36
+ outline-offset: 2px;
37
+ }
38
+ }
39
+
40
+ &-marker {
41
+ flex: none;
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ width: 24px;
46
+ height: 24px;
47
+ border-radius: 50%;
48
+ font-size: 0.75rem;
49
+ font-weight: 600;
50
+ border: 1px solid var(--border-color);
51
+ background: var(--bg-surface-lowest);
52
+ color: var(--text-muted);
53
+ }
54
+
55
+ &-text {
56
+ display: flex;
57
+ flex-direction: column;
58
+ min-width: 0;
59
+ line-height: 1.3;
60
+ }
61
+
62
+ &-label {
63
+ font-size: 0.8125rem;
64
+ font-weight: 500;
65
+ color: var(--text-secondary);
66
+ }
67
+
68
+ &-desc {
69
+ font-size: 0.75rem;
70
+ color: var(--text-muted);
71
+ }
72
+
73
+ &-connector {
74
+ flex: 1 1 auto;
75
+ background: var(--border-color);
76
+ }
77
+
78
+ // States
79
+ &-step.is-active {
80
+ .cny-stepper-marker {
81
+ background: var(--color-primary);
82
+ border-color: var(--color-primary);
83
+ color: var(--color-primary-on);
84
+ }
85
+ .cny-stepper-label { color: var(--text-primary); font-weight: 600; }
86
+ }
87
+ &-step.is-complete {
88
+ .cny-stepper-marker {
89
+ background: var(--color-success);
90
+ border-color: var(--color-success);
91
+ color: var(--color-success-on);
92
+ }
93
+ .cny-stepper-label { color: var(--text-primary); }
94
+ & + .cny-stepper-step .cny-stepper-connector,
95
+ .cny-stepper-connector { background: var(--color-success); }
96
+ }
97
+
98
+ // Horizontal
99
+ &-horizontal {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: $space-2;
103
+
104
+ .cny-stepper-step { flex: 0 1 auto; }
105
+ .cny-stepper-step:not(:last-child) { flex: 1 1 0; }
106
+ .cny-stepper-connector { height: 2px; margin: 0 $space-2; min-width: 12px; }
107
+ }
108
+
109
+ // Vertical
110
+ &-vertical {
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: $space-2;
114
+
115
+ .cny-stepper-step { flex-direction: column; align-items: flex-start; gap: 4px; }
116
+ .cny-stepper-connector { width: 2px; min-height: 16px; margin-left: 11px; }
117
+ }
118
+
119
+ // Sizes
120
+ &-sm {
121
+ .cny-stepper-marker { width: 20px; height: 20px; font-size: 0.7rem; }
122
+ .cny-stepper-label { font-size: 0.75rem; }
123
+ .cny-stepper-desc { font-size: 0.7rem; }
124
+ }
125
+ }