kmaterialize 2.3.3-1.0.21 → 2.3.3-1.0.22
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/components/kanban/_kanban.scss +69 -0
- package/components/kanban/kanban.ts +57 -8
- package/dist/css/materialize.colors.min.css +1 -1
- package/dist/css/materialize.css +70 -1
- package/dist/css/materialize.min.css +2 -2
- package/dist/css/materialize.min.css.map +1 -1
- package/dist/js/materialize.cjs.js +62 -10
- package/dist/js/materialize.d.ts +5 -1
- package/dist/js/materialize.js +62 -10
- package/dist/js/materialize.min.js +2 -2
- package/dist/js/materialize.mjs +62 -10
- package/package.json +1 -1
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
.kanban-card {
|
|
74
|
+
--kanban-card-accent: var(--md-sys-color-primary);
|
|
74
75
|
position: relative;
|
|
75
76
|
display: flex;
|
|
76
77
|
flex-direction: column;
|
|
@@ -83,6 +84,8 @@
|
|
|
83
84
|
box-shadow: var(--md-sys-elevation-level1, 0 1px 2px rgba(0, 0, 0, 0.14));
|
|
84
85
|
cursor: grab;
|
|
85
86
|
user-select: none;
|
|
87
|
+
overflow: hidden;
|
|
88
|
+
transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease;
|
|
86
89
|
|
|
87
90
|
&:active,
|
|
88
91
|
&.is-dragging {
|
|
@@ -91,12 +94,78 @@
|
|
|
91
94
|
|
|
92
95
|
&.is-dragging {
|
|
93
96
|
opacity: 0.45;
|
|
97
|
+
box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
&:focus-visible {
|
|
97
101
|
outline: 2px solid var(--md-sys-color-primary);
|
|
98
102
|
outline-offset: 2px;
|
|
99
103
|
}
|
|
104
|
+
|
|
105
|
+
&.kanban-card-accent {
|
|
106
|
+
&::after {
|
|
107
|
+
position: absolute;
|
|
108
|
+
right: 0;
|
|
109
|
+
bottom: 0;
|
|
110
|
+
left: 0;
|
|
111
|
+
height: 0.25rem;
|
|
112
|
+
background: var(--kanban-card-accent);
|
|
113
|
+
content: '';
|
|
114
|
+
pointer-events: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&.kanban-card-accent-top::after {
|
|
119
|
+
top: 0;
|
|
120
|
+
bottom: auto;
|
|
121
|
+
left: 0;
|
|
122
|
+
width: 100%;
|
|
123
|
+
height: 0.25rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&.kanban-card-accent-right::after {
|
|
127
|
+
top: 0;
|
|
128
|
+
right: 0;
|
|
129
|
+
bottom: 0;
|
|
130
|
+
left: auto;
|
|
131
|
+
width: 0.25rem;
|
|
132
|
+
height: 100%;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&.kanban-card-accent-left::after {
|
|
136
|
+
top: 0;
|
|
137
|
+
right: auto;
|
|
138
|
+
bottom: 0;
|
|
139
|
+
left: 0;
|
|
140
|
+
width: 0.25rem;
|
|
141
|
+
height: 100%;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&.is-disabled,
|
|
145
|
+
&[aria-disabled='true'] {
|
|
146
|
+
cursor: not-allowed;
|
|
147
|
+
opacity: 0.55;
|
|
148
|
+
filter: saturate(0.55);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.kanban-drag-image {
|
|
153
|
+
position: fixed !important;
|
|
154
|
+
top: -10000px !important;
|
|
155
|
+
left: -10000px !important;
|
|
156
|
+
z-index: -1;
|
|
157
|
+
pointer-events: none;
|
|
158
|
+
transform: rotate(2deg) scale(1.015);
|
|
159
|
+
transform-origin: center;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.kanban-drop-preview {
|
|
163
|
+
min-height: 4rem;
|
|
164
|
+
box-sizing: border-box;
|
|
165
|
+
border: 2px dashed var(--md-sys-color-primary);
|
|
166
|
+
border-radius: 0.75rem;
|
|
167
|
+
background: color-mix(in srgb, var(--md-sys-color-primary-container) 45%, transparent);
|
|
168
|
+
pointer-events: none;
|
|
100
169
|
}
|
|
101
170
|
|
|
102
171
|
.kanban-card-title {
|
|
@@ -21,13 +21,24 @@ const _defaults: KanbanOptions = {
|
|
|
21
21
|
export class Kanban extends Component<KanbanOptions> {
|
|
22
22
|
private _draggedCard: HTMLElement | null = null;
|
|
23
23
|
private _dragSourceColumn: HTMLElement | null = null;
|
|
24
|
+
private _dropPreview: HTMLElement | null = null;
|
|
25
|
+
private _dragImage: HTMLElement | null = null;
|
|
26
|
+
private _previewHeight = 64;
|
|
24
27
|
|
|
25
28
|
private _onDragStart = (event: DragEvent) => {
|
|
26
29
|
const card = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
|
|
27
|
-
if (!card || !this.options.draggable) return;
|
|
30
|
+
if (!card || !this.options.draggable || card.classList.contains('is-disabled') || card.getAttribute('aria-disabled') === 'true') return;
|
|
28
31
|
this._draggedCard = card;
|
|
29
32
|
this._dragSourceColumn = card.closest<HTMLElement>('.kanban-column');
|
|
33
|
+
this._previewHeight = Math.max(64, Math.round(card.getBoundingClientRect().height));
|
|
30
34
|
card.classList.add('is-dragging');
|
|
35
|
+
this._dragImage = card.cloneNode(true) as HTMLElement;
|
|
36
|
+
this._dragImage.classList.remove('is-dragging');
|
|
37
|
+
this._dragImage.classList.add('kanban-drag-image');
|
|
38
|
+
this._dragImage.setAttribute('aria-hidden', 'true');
|
|
39
|
+
this._dragImage.style.width = `${card.getBoundingClientRect().width}px`;
|
|
40
|
+
document.body.appendChild(this._dragImage);
|
|
41
|
+
event.dataTransfer?.setDragImage(this._dragImage, card.offsetWidth / 2, card.offsetHeight / 2);
|
|
31
42
|
event.dataTransfer?.setData('text/plain', card.dataset.kanbanCard || '');
|
|
32
43
|
if (event.dataTransfer) event.dataTransfer.effectAllowed = 'move';
|
|
33
44
|
};
|
|
@@ -40,6 +51,7 @@ export class Kanban extends Component<KanbanOptions> {
|
|
|
40
51
|
if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
|
|
41
52
|
this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
|
|
42
53
|
column.classList.add('is-drag-over');
|
|
54
|
+
this._updateDropPreview(column, event);
|
|
43
55
|
};
|
|
44
56
|
|
|
45
57
|
private _onDrop = (event: DragEvent) => {
|
|
@@ -50,15 +62,18 @@ export class Kanban extends Component<KanbanOptions> {
|
|
|
50
62
|
const body = column.querySelector<HTMLElement>('.kanban-column-body') || column;
|
|
51
63
|
const targetCard = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
|
|
52
64
|
const source = this._dragSourceColumn;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
body.insertBefore(
|
|
65
|
+
const movedCard = this._draggedCard;
|
|
66
|
+
if (this._dropPreview?.parentElement === body) {
|
|
67
|
+
body.insertBefore(movedCard, this._dropPreview);
|
|
68
|
+
this._dropPreview.remove();
|
|
69
|
+
} else if (targetCard && targetCard !== movedCard && targetCard.parentElement === body) {
|
|
70
|
+
body.insertBefore(movedCard, targetCard);
|
|
56
71
|
} else {
|
|
57
|
-
body.appendChild(
|
|
72
|
+
body.appendChild(movedCard);
|
|
58
73
|
}
|
|
59
74
|
this._clearDragState();
|
|
60
75
|
this._updateCounts();
|
|
61
|
-
if (source && source !== column) this.options.onMove?.({ card:
|
|
76
|
+
if (source && source !== column) this.options.onMove?.({ card: movedCard, from: source, to: column });
|
|
62
77
|
};
|
|
63
78
|
|
|
64
79
|
private _onDragEnd = () => this._clearDragState();
|
|
@@ -93,8 +108,14 @@ export class Kanban extends Component<KanbanOptions> {
|
|
|
93
108
|
if (body) body.setAttribute('role', 'list');
|
|
94
109
|
column.querySelectorAll<HTMLElement>('.kanban-card').forEach((card) => {
|
|
95
110
|
card.setAttribute('role', 'listitem');
|
|
96
|
-
card.
|
|
97
|
-
|
|
111
|
+
const disabled = card.classList.contains('is-disabled') || card.getAttribute('aria-disabled') === 'true';
|
|
112
|
+
card.setAttribute('tabindex', disabled ? '-1' : '0');
|
|
113
|
+
if (disabled) {
|
|
114
|
+
card.setAttribute('aria-disabled', 'true');
|
|
115
|
+
card.draggable = false;
|
|
116
|
+
} else if (this.options.draggable) {
|
|
117
|
+
card.draggable = true;
|
|
118
|
+
}
|
|
98
119
|
});
|
|
99
120
|
});
|
|
100
121
|
this._updateCounts();
|
|
@@ -108,10 +129,15 @@ export class Kanban extends Component<KanbanOptions> {
|
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
private _clearDragState() {
|
|
132
|
+
this._dragImage?.remove();
|
|
133
|
+
this._dragImage = null;
|
|
134
|
+
this._dropPreview?.remove();
|
|
135
|
+
this._dropPreview = null;
|
|
111
136
|
this._draggedCard?.classList.remove('is-dragging');
|
|
112
137
|
this.el.querySelectorAll('.kanban-column.is-drag-over').forEach((item) => item.classList.remove('is-drag-over'));
|
|
113
138
|
this._draggedCard = null;
|
|
114
139
|
this._dragSourceColumn = null;
|
|
140
|
+
this._previewHeight = 64;
|
|
115
141
|
}
|
|
116
142
|
|
|
117
143
|
private _updateCounts() {
|
|
@@ -119,9 +145,32 @@ export class Kanban extends Component<KanbanOptions> {
|
|
|
119
145
|
const count = column.querySelector<HTMLElement>('.kanban-column-count');
|
|
120
146
|
const body = column.querySelector<HTMLElement>('.kanban-column-body');
|
|
121
147
|
if (count && body) count.textContent = String(body.querySelectorAll(':scope > .kanban-card').length);
|
|
148
|
+
const empty = body?.querySelector<HTMLElement>('.kanban-empty');
|
|
149
|
+
if (empty && body) empty.hidden = body.querySelectorAll(':scope > .kanban-card').length > 0;
|
|
122
150
|
});
|
|
123
151
|
}
|
|
124
152
|
|
|
153
|
+
private _updateDropPreview(column: HTMLElement, event: DragEvent) {
|
|
154
|
+
const body = column.querySelector<HTMLElement>('.kanban-column-body') || column;
|
|
155
|
+
const targetCard = (event.target as HTMLElement | null)?.closest<HTMLElement>('.kanban-card');
|
|
156
|
+
if (targetCard === this._draggedCard) return;
|
|
157
|
+
if (!this._dropPreview) {
|
|
158
|
+
this._dropPreview = document.createElement('div');
|
|
159
|
+
this._dropPreview.className = 'kanban-drop-preview';
|
|
160
|
+
this._dropPreview.setAttribute('aria-hidden', 'true');
|
|
161
|
+
}
|
|
162
|
+
// Keep the preview tied to the dragged card's original height. Using the
|
|
163
|
+
// hovered card's height makes the placeholder jump as the pointer crosses
|
|
164
|
+
// cards with different content lengths.
|
|
165
|
+
this._dropPreview.style.height = `${this._previewHeight}px`;
|
|
166
|
+
if (targetCard && targetCard.parentElement === body) {
|
|
167
|
+
const box = targetCard.getBoundingClientRect();
|
|
168
|
+
body.insertBefore(this._dropPreview, event.clientY < box.top + box.height / 2 ? targetCard : targetCard.nextSibling);
|
|
169
|
+
} else if (this._dropPreview.parentElement !== body) {
|
|
170
|
+
body.appendChild(this._dropPreview);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
125
174
|
destroy() {
|
|
126
175
|
this._clearDragState();
|
|
127
176
|
this.el.removeEventListener('dragstart', this._onDragStart);
|
package/dist/css/materialize.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Materialize v2.3.3-1.0.
|
|
2
|
+
* Materialize v2.3.3-1.0.22 (https://materializeweb.com)
|
|
3
3
|
* Copyright 2014-2026 Materialize
|
|
4
4
|
* MIT License (https://raw.githubusercontent.com/materializecss/materialize/master/LICENSE)
|
|
5
5
|
*/
|
|
@@ -13983,6 +13983,7 @@ button.btn-floating {
|
|
|
13983
13983
|
}
|
|
13984
13984
|
|
|
13985
13985
|
.kanban-card {
|
|
13986
|
+
--kanban-card-accent: var(--md-sys-color-primary);
|
|
13986
13987
|
position: relative;
|
|
13987
13988
|
display: -webkit-box;
|
|
13988
13989
|
display: -webkit-flex;
|
|
@@ -14007,6 +14008,11 @@ button.btn-floating {
|
|
|
14007
14008
|
-moz-user-select: none;
|
|
14008
14009
|
-ms-user-select: none;
|
|
14009
14010
|
user-select: none;
|
|
14011
|
+
overflow: hidden;
|
|
14012
|
+
-webkit-transition: opacity 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
|
|
14013
|
+
transition: opacity 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
|
|
14014
|
+
transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease;
|
|
14015
|
+
transition: transform 160ms ease, opacity 160ms ease, box-shadow 160ms ease, -webkit-transform 160ms ease, -webkit-box-shadow 160ms ease;
|
|
14010
14016
|
}
|
|
14011
14017
|
.kanban-card:active, .kanban-card.is-dragging {
|
|
14012
14018
|
cursor: -webkit-grabbing;
|
|
@@ -14014,11 +14020,74 @@ button.btn-floating {
|
|
|
14014
14020
|
}
|
|
14015
14021
|
.kanban-card.is-dragging {
|
|
14016
14022
|
opacity: 0.45;
|
|
14023
|
+
-webkit-box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
|
|
14024
|
+
box-shadow: var(--md-sys-elevation-level3, 0 8px 18px rgba(0, 0, 0, 0.2));
|
|
14017
14025
|
}
|
|
14018
14026
|
.kanban-card:focus-visible {
|
|
14019
14027
|
outline: 2px solid var(--md-sys-color-primary);
|
|
14020
14028
|
outline-offset: 2px;
|
|
14021
14029
|
}
|
|
14030
|
+
.kanban-card.kanban-card-accent::after {
|
|
14031
|
+
position: absolute;
|
|
14032
|
+
right: 0;
|
|
14033
|
+
bottom: 0;
|
|
14034
|
+
left: 0;
|
|
14035
|
+
height: 0.25rem;
|
|
14036
|
+
background: var(--kanban-card-accent);
|
|
14037
|
+
content: "";
|
|
14038
|
+
pointer-events: none;
|
|
14039
|
+
}
|
|
14040
|
+
.kanban-card.kanban-card-accent-top::after {
|
|
14041
|
+
top: 0;
|
|
14042
|
+
bottom: auto;
|
|
14043
|
+
left: 0;
|
|
14044
|
+
width: 100%;
|
|
14045
|
+
height: 0.25rem;
|
|
14046
|
+
}
|
|
14047
|
+
.kanban-card.kanban-card-accent-right::after {
|
|
14048
|
+
top: 0;
|
|
14049
|
+
right: 0;
|
|
14050
|
+
bottom: 0;
|
|
14051
|
+
left: auto;
|
|
14052
|
+
width: 0.25rem;
|
|
14053
|
+
height: 100%;
|
|
14054
|
+
}
|
|
14055
|
+
.kanban-card.kanban-card-accent-left::after {
|
|
14056
|
+
top: 0;
|
|
14057
|
+
right: auto;
|
|
14058
|
+
bottom: 0;
|
|
14059
|
+
left: 0;
|
|
14060
|
+
width: 0.25rem;
|
|
14061
|
+
height: 100%;
|
|
14062
|
+
}
|
|
14063
|
+
.kanban-card.is-disabled, .kanban-card[aria-disabled=true] {
|
|
14064
|
+
cursor: not-allowed;
|
|
14065
|
+
opacity: 0.55;
|
|
14066
|
+
-webkit-filter: saturate(0.55);
|
|
14067
|
+
filter: saturate(0.55);
|
|
14068
|
+
}
|
|
14069
|
+
|
|
14070
|
+
.kanban-drag-image {
|
|
14071
|
+
position: fixed !important;
|
|
14072
|
+
top: -10000px !important;
|
|
14073
|
+
left: -10000px !important;
|
|
14074
|
+
z-index: -1;
|
|
14075
|
+
pointer-events: none;
|
|
14076
|
+
-webkit-transform: rotate(2deg) scale(1.015);
|
|
14077
|
+
transform: rotate(2deg) scale(1.015);
|
|
14078
|
+
-webkit-transform-origin: center;
|
|
14079
|
+
transform-origin: center;
|
|
14080
|
+
}
|
|
14081
|
+
|
|
14082
|
+
.kanban-drop-preview {
|
|
14083
|
+
min-height: 4rem;
|
|
14084
|
+
-webkit-box-sizing: border-box;
|
|
14085
|
+
box-sizing: border-box;
|
|
14086
|
+
border: 2px dashed var(--md-sys-color-primary);
|
|
14087
|
+
border-radius: 0.75rem;
|
|
14088
|
+
background: color-mix(in srgb, var(--md-sys-color-primary-container) 45%, transparent);
|
|
14089
|
+
pointer-events: none;
|
|
14090
|
+
}
|
|
14022
14091
|
|
|
14023
14092
|
.kanban-card-title {
|
|
14024
14093
|
margin: 0;
|