@flux-ui/components 3.0.0-next.57 → 3.0.0-next.58

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,5 +1,11 @@
1
- import { FluxKanbanMoveEvent } from '@flux-ui/types';
1
+ import { FluxKanbanMoveColumnEvent, FluxKanbanMoveEvent } from '@flux-ui/types';
2
2
  import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
3
+ type __VLS_Props = {
4
+ readonly ariaLabel?: string;
5
+ readonly canMove?: (event: FluxKanbanMoveEvent) => boolean;
6
+ readonly disabled?: boolean;
7
+ readonly reorderableColumns?: boolean;
8
+ };
3
9
  declare function __VLS_template(): {
4
10
  attrs: Partial<{}>;
5
11
  slots: Readonly<{
@@ -7,15 +13,21 @@ declare function __VLS_template(): {
7
13
  }> & {
8
14
  default?(): any;
9
15
  };
10
- refs: {};
16
+ refs: {
17
+ root: HTMLDivElement;
18
+ };
11
19
  rootEl: HTMLDivElement;
12
20
  };
13
21
  type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
14
- declare const __VLS_component: DefineComponent<{}, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
22
+ declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {
15
23
  move: (args_0: FluxKanbanMoveEvent) => any;
16
- }, string, PublicProps, Readonly<{}> & Readonly<{
24
+ moveColumn: (args_0: FluxKanbanMoveColumnEvent) => any;
25
+ }, string, PublicProps, Readonly<__VLS_Props> & Readonly<{
17
26
  onMove?: (args_0: FluxKanbanMoveEvent) => any;
18
- }>, {}, {}, {}, {}, string, ComponentProvideOptions, true, {}, HTMLDivElement>;
27
+ onMoveColumn?: (args_0: FluxKanbanMoveColumnEvent) => any;
28
+ }>, {}, {}, {}, {}, string, ComponentProvideOptions, true, {
29
+ root: HTMLDivElement;
30
+ }, HTMLDivElement>;
19
31
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
20
32
  export default _default;
21
33
  type __VLS_WithTemplateSlots<T, S> = T & {
@@ -2,6 +2,7 @@ import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOp
2
2
  type __VLS_Props = {
3
3
  readonly cardId: string | number;
4
4
  readonly columnId: string | number;
5
+ readonly disabled?: boolean;
5
6
  };
6
7
  declare function __VLS_template(): {
7
8
  attrs: Partial<{}>;
@@ -1,6 +1,7 @@
1
1
  import { DefineComponent, ComponentOptionsMixin, PublicProps, ComponentProvideOptions } from 'vue';
2
2
  type __VLS_Props = {
3
3
  readonly columnId: string | number;
4
+ readonly disabled?: boolean;
4
5
  readonly label: string;
5
6
  };
6
7
  declare function __VLS_template(): {
@@ -9,16 +10,26 @@ declare function __VLS_template(): {
9
10
  default?(): any;
10
11
  header?(): any;
11
12
  actions?(): any;
13
+ empty?(): any;
14
+ footer?(): any;
12
15
  }> & {
13
16
  default?(): any;
14
17
  header?(): any;
15
18
  actions?(): any;
19
+ empty?(): any;
20
+ footer?(): any;
21
+ };
22
+ refs: {
23
+ root: HTMLDivElement;
24
+ body: HTMLDivElement;
16
25
  };
17
- refs: {};
18
26
  rootEl: HTMLDivElement;
19
27
  };
20
28
  type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
21
- declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {}, HTMLDivElement>;
29
+ declare const __VLS_component: DefineComponent<__VLS_Props, {}, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, {}, string, PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, ComponentProvideOptions, false, {
30
+ root: HTMLDivElement;
31
+ body: HTMLDivElement;
32
+ }, HTMLDivElement>;
22
33
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
23
34
  export default _default;
24
35
  type __VLS_WithTemplateSlots<T, S> = T & {
@@ -7,7 +7,7 @@ type UseAsyncFilterOptionsParams = {
7
7
  fetchRelevant(): Promise<FluxFilterOptionRow[]>;
8
8
  fetchSearch(searchQuery: string): Promise<FluxFilterOptionRow[]>;
9
9
  };
10
- export default function ({ currentValueIds, modelSearch, fetchOptions: fetchOptionsProp, fetchRelevant: fetchRelevantProp, fetchSearch: fetchSearchProp }: UseAsyncFilterOptionsParams): {
10
+ export default function (params: UseAsyncFilterOptionsParams): {
11
11
  isLoading: ComputedRef<boolean>;
12
12
  options: ComputedRef<FluxFilterOptionRow[]>;
13
13
  };
@@ -1,7 +1,17 @@
1
- import { FluxKanbanMoveEvent } from '@flux-ui/types';
1
+ import { FluxKanbanMoveColumnEvent, FluxKanbanMoveEvent } from '@flux-ui/types';
2
+ import { Ref } from 'vue';
2
3
  import { FluxKanbanInjection } from '../../data/di';
4
+ export type UseKanbanOptions = {
5
+ readonly disabled: Ref<boolean>;
6
+ readonly reorderableColumns: Ref<boolean>;
7
+ readonly canMove?: Ref<((event: FluxKanbanMoveEvent) => boolean) | undefined>;
8
+ readonly onMove: (event: FluxKanbanMoveEvent) => void;
9
+ readonly onMoveColumn: (event: FluxKanbanMoveColumnEvent) => void;
10
+ readonly onAnnounce: (message: string) => void;
11
+ };
3
12
  /**
4
13
  * Internal composable for managing kanban drag-and-drop state.
5
- * Provides card registration, drag tracking, and drop target management.
14
+ * Provides card registration, drag tracking, drop target management,
15
+ * keyboard drag-and-drop, column reordering, drop validation and auto-scroll.
6
16
  */
7
- export declare function useKanban(onMove: (event: FluxKanbanMoveEvent) => void): FluxKanbanInjection;
17
+ export declare function useKanban(options: UseKanbanOptions): FluxKanbanInjection;
package/dist/data/di.d.ts CHANGED
@@ -9,24 +9,53 @@ export declare const FluxFilterInjectionKey: InjectionKey<FluxFilterInjection>;
9
9
  export declare const FluxFormFieldInjectionKey: InjectionKey<FluxFormFieldInjection>;
10
10
  export declare const FluxTableInjectionKey: InjectionKey<FluxTableInjection>;
11
11
  export declare const FluxTooltipInjectionKey: InjectionKey<FluxTooltipInjection>;
12
+ export type FluxKanbanDragMode = 'pointer' | 'keyboard';
12
13
  export type FluxKanbanDragState = {
14
+ readonly mode: FluxKanbanDragMode;
13
15
  readonly cardId: string | number;
14
16
  readonly fromColumnId: string | number;
15
17
  readonly dropColumnId: string | number | null;
16
18
  readonly beforeCardId: string | number | null;
19
+ readonly originBeforeCardId?: string | number | null;
17
20
  };
21
+ export type FluxKanbanColumnDragState = {
22
+ readonly columnId: string | number;
23
+ readonly dropBeforeColumnId: string | number | null;
24
+ };
25
+ export type FluxKanbanKeyboardDirection = 'up' | 'down' | 'left' | 'right';
18
26
  export type FluxKanbanInjection = {
27
+ readonly disabled: Ref<boolean>;
28
+ readonly reorderableColumns: Ref<boolean>;
19
29
  readonly dragState: Ref<FluxKanbanDragState | null>;
30
+ readonly columnDragState: Ref<FluxKanbanColumnDragState | null>;
31
+ readonly isDropAllowed: Ref<boolean>;
20
32
  registerCard(element: Element, cardId: string | number): void;
21
33
  unregisterCard(element: Element): void;
22
34
  getCardInfo(element: Element): {
23
35
  readonly cardId: string | number;
24
36
  } | undefined;
37
+ registerColumn(element: Element, columnId: string | number): void;
38
+ unregisterColumn(element: Element): void;
39
+ getColumnInfo(element: Element): {
40
+ readonly columnId: string | number;
41
+ } | undefined;
42
+ setBoardElement(element: Element | null): void;
43
+ setColumnBodyElement(columnId: string | number, element: Element | null): void;
25
44
  startDrag(cardId: string | number, fromColumnId: string | number): void;
26
45
  endDrag(): void;
27
46
  updateDropTarget(columnId: string | number, beforeCardId: string | number | null): void;
28
47
  clearDropTarget(): void;
29
48
  commitDrop(): void;
49
+ grabCard(cardId: string | number, fromColumnId: string | number): void;
50
+ moveKeyboard(direction: FluxKanbanKeyboardDirection): void;
51
+ commitKeyboardDrop(): void;
52
+ cancelKeyboardDrop(): void;
53
+ isCardGrabbed(cardId: string | number): boolean;
54
+ startColumnDrag(columnId: string | number): void;
55
+ endColumnDrag(): void;
56
+ updateColumnDropTarget(beforeColumnId: string | number | null): void;
57
+ commitColumnDrop(): void;
58
+ onPointerMove(clientX: number, clientY: number): void;
30
59
  };
31
60
  export type FluxAdaptiveGroupChild = {
32
61
  readonly priority: Ref<number>;
package/dist/index.css CHANGED
@@ -5242,51 +5242,49 @@ tfoot .table-cell {
5242
5242
 
5243
5243
  .info-body {
5244
5244
  align-items: center;
5245
- }.kanban {
5245
+ }/* region root */
5246
+ .kanban {
5247
+ position: relative;
5246
5248
  display: flex;
5247
5249
  flex-flow: row;
5248
5250
  gap: 15px;
5251
+ block-size: 100%;
5252
+ inline-size: 100%;
5249
5253
  overflow-x: auto;
5250
5254
  padding-bottom: 6px;
5251
- }.kanban-card {
5252
- position: relative;
5253
- padding: 12px;
5254
- background: var(--gray-25);
5255
- border: 1px solid var(--gray-200);
5256
- border-radius: var(--radius);
5257
- cursor: grab;
5258
- transition: opacity 180ms var(--swift-out), box-shadow 180ms var(--swift-out);
5259
- user-select: none;
5260
- }
5261
- .kanban-card:active {
5262
- cursor: grabbing;
5263
- }
5264
- .kanban-card:hover {
5265
- box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
5266
5255
  }
5267
5256
 
5268
- .is-dragging {
5269
- opacity: 0.4;
5270
- cursor: grabbing;
5257
+ .kanban-live-region {
5258
+ position: absolute;
5259
+ width: 1px;
5260
+ height: 1px;
5261
+ margin: -1px;
5262
+ padding: 0;
5263
+ border: 0;
5264
+ overflow: hidden;
5265
+ clip: rect(0, 0, 0, 0);
5266
+ white-space: nowrap;
5271
5267
  }
5272
5268
 
5273
- .is-drop-before::before {
5274
- content: "";
5275
- position: absolute;
5276
- inset-inline: 0;
5277
- top: -6px;
5278
- height: 2px;
5279
- border-radius: 999px;
5280
- background: var(--primary-500);
5281
- }.kanban-column {
5269
+ /* endregion */
5270
+ /* region column */
5271
+ .kanban-column {
5282
5272
  display: flex;
5283
5273
  flex-flow: column;
5284
- flex-shrink: 0;
5285
- width: 280px;
5274
+ flex: 1 0 300px;
5286
5275
  background: var(--gray-100);
5287
5276
  border: 1px solid var(--gray-200);
5288
5277
  border-radius: var(--radius);
5289
5278
  overflow: hidden;
5279
+ transition: opacity 180ms var(--swift-out);
5280
+ }
5281
+
5282
+ .kanban-column.is-column-dragging {
5283
+ opacity: 0.4;
5284
+ }
5285
+
5286
+ .kanban-column.is-column-drop-before {
5287
+ box-shadow: -3px 0 0 var(--primary-500);
5290
5288
  }
5291
5289
 
5292
5290
  .kanban-column-header {
@@ -5295,6 +5293,20 @@ tfoot .table-cell {
5295
5293
  gap: 9px;
5296
5294
  padding: 12px 15px;
5297
5295
  border-bottom: 1px solid var(--gray-200);
5296
+ outline: 2px solid rgb(from var(--primary-600) r g b/0);
5297
+ outline-offset: 0;
5298
+ }
5299
+ .kanban-column-header:focus-visible {
5300
+ outline-color: var(--primary-600);
5301
+ outline-offset: -2;
5302
+ }
5303
+
5304
+ .kanban-column.is-reorderable .kanban-column-header {
5305
+ cursor: grab;
5306
+ }
5307
+
5308
+ .kanban-column.is-reorderable .kanban-column-header:active {
5309
+ cursor: grabbing;
5298
5310
  }
5299
5311
 
5300
5312
  .kanban-column-label {
@@ -5321,12 +5333,120 @@ tfoot .table-cell {
5321
5333
  background: rgb(from var(--primary-500) r g b/0.06);
5322
5334
  }
5323
5335
 
5336
+ .is-over.is-drop-disallowed .kanban-column-body {
5337
+ background: rgb(from var(--danger-500) r g b/0.06);
5338
+ cursor: not-allowed;
5339
+ }
5340
+
5341
+ .is-board-dragging .kanban-column:not(.is-over):not(.is-disabled) .kanban-column-body {
5342
+ background: rgb(from var(--primary-500) r g b/0.02);
5343
+ }
5344
+
5345
+ .kanban-column.is-disabled {
5346
+ opacity: 0.6;
5347
+ cursor: not-allowed;
5348
+ }
5349
+
5350
+ .kanban-column.is-disabled .kanban-column-body {
5351
+ pointer-events: none;
5352
+ }
5353
+
5354
+ .kanban-column-empty {
5355
+ display: flex;
5356
+ flex: 1;
5357
+ align-items: center;
5358
+ justify-content: center;
5359
+ padding: 18px 12px;
5360
+ font-size: 0.8125rem;
5361
+ color: var(--gray-500);
5362
+ text-align: center;
5363
+ }
5364
+
5365
+ .kanban-column-footer {
5366
+ padding: 9px 15px;
5367
+ border-top: 1px solid var(--gray-200);
5368
+ }
5369
+
5324
5370
  .kanban-drop-indicator {
5371
+ flex-shrink: 0;
5325
5372
  height: 2px;
5326
5373
  border-radius: 999px;
5374
+ background: transparent;
5375
+ transition: background 180ms var(--swift-out);
5376
+ }
5377
+
5378
+ .is-drop-end-active {
5327
5379
  background: var(--primary-500);
5328
- flex-shrink: 0;
5329
- }.item {
5380
+ }
5381
+
5382
+ .is-drop-end-active.is-drop-end-disallowed {
5383
+ background: var(--danger-500);
5384
+ }
5385
+
5386
+ /* endregion */
5387
+ /* region card */
5388
+ .kanban-card {
5389
+ position: relative;
5390
+ padding: 12px;
5391
+ background: var(--gray-25);
5392
+ border: 1px solid var(--gray-200);
5393
+ border-radius: var(--radius);
5394
+ cursor: grab;
5395
+ scroll-margin: 9px;
5396
+ transition: opacity 180ms var(--swift-out), box-shadow 180ms var(--swift-out), transform 180ms var(--swift-out);
5397
+ user-select: none;
5398
+ outline: 2px solid rgb(from var(--primary-600) r g b/0);
5399
+ outline-offset: 0;
5400
+ }
5401
+ .kanban-card:focus-visible {
5402
+ outline-color: var(--primary-600);
5403
+ outline-offset: -2;
5404
+ }
5405
+ .kanban-card:active {
5406
+ cursor: grabbing;
5407
+ }
5408
+ .kanban-card:hover {
5409
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
5410
+ }
5411
+
5412
+ .kanban-card.is-disabled {
5413
+ cursor: not-allowed;
5414
+ opacity: 0.6;
5415
+ }
5416
+ .kanban-card.is-disabled:hover {
5417
+ box-shadow: none;
5418
+ }
5419
+ .kanban-card.is-disabled:active {
5420
+ cursor: not-allowed;
5421
+ }
5422
+
5423
+ .is-dragging {
5424
+ opacity: 0.4;
5425
+ cursor: grabbing;
5426
+ }
5427
+
5428
+ .is-grabbed {
5429
+ transform: scale(1.04);
5430
+ background: var(--surface);
5431
+ box-shadow: 0 0 0 2px var(--primary-500), 0 8px 24px rgba(0, 0, 0, 0.15);
5432
+ z-index: 1;
5433
+ }
5434
+
5435
+ .is-drop-before::before {
5436
+ content: "";
5437
+ position: absolute;
5438
+ inset-inline: 0;
5439
+ top: -6px;
5440
+ height: 2px;
5441
+ border-radius: 999px;
5442
+ background: var(--primary-500);
5443
+ }
5444
+
5445
+ .is-drop-before.is-drop-before-disallowed::before {
5446
+ background: var(--danger-500);
5447
+ }
5448
+
5449
+ /* endregion */.item {
5330
5450
  display: flex;
5331
5451
  flex-flow: row nowrap;
5332
5452
  gap: 18px;