@lotics/ui 46.14.1 → 47.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.
- package/AGENTS.md +20 -0
- package/MIGRATION.md +58 -0
- package/docs/catalog.md +38 -9
- package/docs/composition.md +52 -0
- package/docs/reviewing.md +19 -2
- package/docs/templates.md +8 -2
- package/examples/tpl_calendar.tsx +22 -29
- package/package.json +1 -1
- package/src/board.tsx +1 -2
- package/src/calendar/agenda_view.tsx +136 -0
- package/src/calendar/calendar_toolbar.tsx +84 -0
- package/src/calendar/calendar_view.tsx +196 -103
- package/src/calendar/context.ts +47 -0
- package/src/calendar/dates.ts +36 -6
- package/src/calendar/event_chip.tsx +141 -0
- package/src/calendar/index.ts +31 -8
- package/src/calendar/layout.ts +113 -11
- package/src/calendar/month_view.tsx +194 -150
- package/src/calendar/repeat.ts +174 -0
- package/src/calendar/time_grid_view.tsx +182 -202
- package/src/calendar/types.ts +37 -11
- package/src/control_surface.ts +28 -0
- package/src/deadline.ts +10 -0
- package/src/file_row.tsx +26 -3
- package/src/gantt/gantt_view.tsx +212 -119
- package/src/gantt/index.ts +2 -2
- package/src/gantt/scale.ts +38 -2
- package/src/gantt/types.ts +34 -7
- package/src/legend_item.tsx +14 -1
- package/src/locale.tsx +30 -0
- package/src/matrix.tsx +19 -5
- package/src/option_list.tsx +11 -1
- package/src/use_option_list.ts +13 -1
package/src/matrix.tsx
CHANGED
|
@@ -28,6 +28,10 @@ interface MatrixContextValue {
|
|
|
28
28
|
* column budget needs the same number the grid renders with — hard-coding it
|
|
29
29
|
* is how a width budget and the layout drift apart. */
|
|
30
30
|
export const MATRIX_COL_GAP = 3;
|
|
31
|
+
/** Chỗ thở hai bên con số bên trong một ô ma trận. Ô có NỀN, nên con số căn phải
|
|
32
|
+
* cần một khoảng với mép nền; dán sát thì nó đọc như bị cắt. Tiêu đề cột cộng
|
|
33
|
+
* đúng số này vào `paddingRight` của nó để hai bên kết thúc trên một đường. */
|
|
34
|
+
const MATRIX_CELL_PAD = 6;
|
|
31
35
|
|
|
32
36
|
const MatrixContext = createContext<MatrixContextValue | null>(null);
|
|
33
37
|
|
|
@@ -319,10 +323,19 @@ const styles = StyleSheet.create({
|
|
|
319
323
|
},
|
|
320
324
|
cell: {
|
|
321
325
|
flex: 1,
|
|
322
|
-
|
|
326
|
+
// 52 + hai lần MATRIX_CELL_PAD: cái đệm mới ăn vào bề ngang, nên sàn tối
|
|
327
|
+
// thiểu phải cộng thêm đúng ngần ấy, không thì ô chật đi và con số dài nhất
|
|
328
|
+
// là con số đầu tiên bị ép.
|
|
329
|
+
minWidth: 52 + MATRIX_CELL_PAD * 2,
|
|
323
330
|
height: 36,
|
|
324
331
|
borderRadius: 4,
|
|
325
332
|
borderWidth: 2,
|
|
333
|
+
// Con số căn phải trong một ô CÓ NỀN, nên nó cần chỗ thở với mép nền. Trước
|
|
334
|
+
// đây ô không có đệm ngang nào: chữ số cuối dừng cách mép đúng 2px của cái
|
|
335
|
+
// viền, và trên một ô tô màu thì nó đọc ra như bị cắt cụt chứ không như căn
|
|
336
|
+
// phải. Một con số dán vào cạnh khối màu của chính nó là con số trông như
|
|
337
|
+
// còn nữa mà không hiện ra.
|
|
338
|
+
paddingHorizontal: MATRIX_CELL_PAD,
|
|
326
339
|
// STRETCH, not center. The figure inside sets `align="right"`, and a Text
|
|
327
340
|
// centred by its parent SHRINK-WRAPS — so it is exactly as wide as its own
|
|
328
341
|
// glyphs and has nothing to align against. Right-aligning the text while
|
|
@@ -336,10 +349,11 @@ const styles = StyleSheet.create({
|
|
|
336
349
|
},
|
|
337
350
|
colCell: {
|
|
338
351
|
flex: 1,
|
|
339
|
-
minWidth: 52,
|
|
340
|
-
//
|
|
341
|
-
//
|
|
342
|
-
|
|
352
|
+
minWidth: 52 + MATRIX_CELL_PAD * 2,
|
|
353
|
+
// Khớp với tổng phần ô đẩy con số vào: 2px viền cộng cái đệm ngang. Lệch
|
|
354
|
+
// một pixel ở đây là tiêu đề cột và dãy số dưới nó kết thúc ở hai đường x
|
|
355
|
+
// khác nhau — thứ mắt bắt được ngay dù không gọi được tên.
|
|
356
|
+
paddingRight: 2 + MATRIX_CELL_PAD,
|
|
343
357
|
},
|
|
344
358
|
totalCol: {
|
|
345
359
|
// SIZED LIKE A DATA COLUMN, not to a fixed number. It was `width: 64`, and a
|
package/src/option_list.tsx
CHANGED
|
@@ -11,6 +11,7 @@ import { ActivityIndicator } from "./activity_indicator";
|
|
|
11
11
|
import { TextInputField } from "./text_input_field";
|
|
12
12
|
import { useScreenSize } from "./use_screen_size";
|
|
13
13
|
import { useOptionList, type UseOptionListParams } from "./use_option_list";
|
|
14
|
+
import { pickerEmptyOptionLabel } from "./picker_empty_option";
|
|
14
15
|
import { useLoticsLocale } from "./locale";
|
|
15
16
|
import type { PickerOption } from "./picker";
|
|
16
17
|
|
|
@@ -61,7 +62,16 @@ export function OptionList<T extends string, MULTI extends boolean = false, D =
|
|
|
61
62
|
const emptyText = props.emptyText ?? loc.noResults;
|
|
62
63
|
const selectAllLabel = props.selectAllLabel ?? loc.selectAll;
|
|
63
64
|
const deselectAllLabel = props.deselectAllLabel ?? loc.deselectAll;
|
|
64
|
-
|
|
65
|
+
// `Picker` names its clear row from the locale; this list is the same row on
|
|
66
|
+
// the popover path, so it takes the same name from the same helper.
|
|
67
|
+
const emptyWord = useLoticsLocale().picker.emptyOption;
|
|
68
|
+
const list = useOptionList({
|
|
69
|
+
...props,
|
|
70
|
+
emptyOptionLabel: pickerEmptyOptionLabel({
|
|
71
|
+
includeEmptyOption: props.includeEmptyOption,
|
|
72
|
+
localeEmptyOption: emptyWord,
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
65
75
|
const { small } = useScreenSize();
|
|
66
76
|
|
|
67
77
|
// The option rows set `activeIndex` on hover but have no hover-OUT, so entering
|
package/src/use_option_list.ts
CHANGED
|
@@ -65,6 +65,10 @@ export interface UseOptionListParams<
|
|
|
65
65
|
onCustomCommit?: (rawQuery: string) => void;
|
|
66
66
|
/** Single-select: a leading "" row that clears the value. */
|
|
67
67
|
includeEmptyOption?: boolean;
|
|
68
|
+
/** What the clear row is CALLED. `OptionList` supplies the locale's word via
|
|
69
|
+
* `pickerEmptyOptionLabel`; the default keeps older callers rendering as
|
|
70
|
+
* before rather than silently gaining a word they never asked for. */
|
|
71
|
+
emptyOptionLabel?: string;
|
|
68
72
|
enableSelectAll?: boolean;
|
|
69
73
|
}
|
|
70
74
|
|
|
@@ -130,6 +134,7 @@ export function useOptionList<T extends string, MULTI extends boolean = false, D
|
|
|
130
134
|
customOptionPlacement = "bottom",
|
|
131
135
|
onCustomCommit,
|
|
132
136
|
includeEmptyOption = false,
|
|
137
|
+
emptyOptionLabel = "",
|
|
133
138
|
enableSelectAll = false,
|
|
134
139
|
} = params;
|
|
135
140
|
|
|
@@ -211,7 +216,13 @@ export function useOptionList<T extends string, MULTI extends boolean = false, D
|
|
|
211
216
|
kind !== "custom" && (multi ? selectedSet.has(option.value) : option.value === singleValue);
|
|
212
217
|
out.push({ kind, option, index: out.length, selected, nativeID: optionId(out.length) });
|
|
213
218
|
};
|
|
214
|
-
|
|
219
|
+
// The clear row is a CHOICE the reader picks, so it is NAMED — `Picker` has
|
|
220
|
+
// always named it through `pickerEmptyOptionLabel`, and this list did not,
|
|
221
|
+
// so every `Select`/`InlineSelect` offering a way back to empty offered it
|
|
222
|
+
// as a blank row with an empty accessible name.
|
|
223
|
+
if (includeEmptyOption && !multi && !searching) {
|
|
224
|
+
push("empty", { value: "" as T, label: emptyOptionLabel });
|
|
225
|
+
}
|
|
215
226
|
if (customRow && customOptionPlacement === "top") push("custom", customRow);
|
|
216
227
|
for (const o of filtered) push("option", o);
|
|
217
228
|
if (customRow && customOptionPlacement === "bottom") push("custom", customRow);
|
|
@@ -221,6 +232,7 @@ export function useOptionList<T extends string, MULTI extends boolean = false, D
|
|
|
221
232
|
customRow,
|
|
222
233
|
customOptionPlacement,
|
|
223
234
|
includeEmptyOption,
|
|
235
|
+
emptyOptionLabel,
|
|
224
236
|
multi,
|
|
225
237
|
searching,
|
|
226
238
|
selectedSet,
|