@hjmds/design-contracts 1.48.0 → 1.49.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/dist/card.d.ts +5 -0
- package/dist/card.d.ts.map +1 -1
- package/dist/card.js +3 -0
- package/dist/card.js.map +1 -1
- package/dist/catalog.d.ts +34 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +4 -0
- package/dist/catalog.js.map +1 -1
- package/dist/drawing-editor.d.ts +96 -0
- package/dist/drawing-editor.d.ts.map +1 -0
- package/dist/drawing-editor.js +43 -0
- package/dist/drawing-editor.js.map +1 -0
- package/dist/timeline.d.ts +7 -0
- package/dist/timeline.d.ts.map +1 -1
- package/dist/timeline.js +7 -0
- package/dist/timeline.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/drawing-editor.md +14 -0
- package/docs/generated/component-maturity.md +5 -4
- package/docs/generated/renderer-evidence.json +109 -9
- package/docs/generated/renderer-evidence.md +5 -3
- package/docs/generated/showcase-manifest.json +52 -1
- package/docs/timeline.md +13 -0
- package/docs/usage/README.md +2 -1
- package/docs/usage/components/card.md +1 -0
- package/docs/usage/components/drawing-editor.md +133 -0
- package/docs/usage/components/image-choice-group.md +1 -1
- package/docs/usage/components/sheet.md +13 -1
- package/docs/usage/components/timeline.md +27 -3
- package/package.json +6 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const DRAWING_INK_COLORS = ['#333d4b', '#ffffff', '#e03131', '#f08c00', '#ffd43b', '#087f5b', '#3f66a5', '#7048e8', '#9c4668', '#f783ac', '#8d6e63', '#868e96'];
|
|
2
|
+
/** Default background. The person can change it; the chosen background is part of the saved photo. */
|
|
3
|
+
export const DRAWING_PAPER = '#fffaf2';
|
|
4
|
+
/** Background presets: the default paper, light tints that keep ink readable, and one dark ground for light ink. */
|
|
5
|
+
export const DRAWING_BACKGROUND_COLORS = ['#fffaf2', '#ffffff', '#f1f3f5', '#ffe3e3', '#ffdeeb', '#fff3bf', '#d3f9d8', '#c5f6fa', '#d0ebff', '#e5dbff', '#333d4b'];
|
|
6
|
+
export function drawingStrokeColor(stroke, background) {
|
|
7
|
+
return stroke.erase ? background : stroke.color;
|
|
8
|
+
}
|
|
9
|
+
/** Something worth saving: an ink stroke, or a background other than the default paper. */
|
|
10
|
+
export function drawingHasContent(strokes, background) {
|
|
11
|
+
return background !== DRAWING_PAPER || strokes.some(stroke => !stroke.erase);
|
|
12
|
+
}
|
|
13
|
+
export function drawingInkPath(stroke) {
|
|
14
|
+
return stroke.points.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ') + (stroke.points.length === 1 ? ' l0.1,0.1' : '');
|
|
15
|
+
}
|
|
16
|
+
export const emptyDrawing = { past: [], present: [], future: [] };
|
|
17
|
+
/** A stroke, including an eraser, is one undo step. Clearing can also be undone. */
|
|
18
|
+
export function drawingReducer(state, action) {
|
|
19
|
+
if (action.type === 'undo') {
|
|
20
|
+
const previous = state.past.at(-1);
|
|
21
|
+
return previous ? { past: state.past.slice(0, -1), present: previous, future: [state.present, ...state.future] } : state;
|
|
22
|
+
}
|
|
23
|
+
if (action.type === 'redo') {
|
|
24
|
+
const next = state.future[0];
|
|
25
|
+
return next ? { past: [...state.past, state.present], present: next, future: state.future.slice(1) } : state;
|
|
26
|
+
}
|
|
27
|
+
if (action.type === 'clear' && !state.present.length)
|
|
28
|
+
return state;
|
|
29
|
+
return { past: [...state.past, state.present], present: action.type === 'add' ? [...state.present, action.stroke] : [], future: [] };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* One-row colour strip for the drawing toolbar: colours the person picked from the full picker this session come
|
|
33
|
+
* first (newest first, at most four), then the presets. Recent colours are not stored; the drawing itself is.
|
|
34
|
+
*/
|
|
35
|
+
export function drawingQuickColors(recent) {
|
|
36
|
+
return [...new Set([...recent.slice(0, 4), ...DRAWING_INK_COLORS])];
|
|
37
|
+
}
|
|
38
|
+
/** Shared editor geometry; the 400px cap leaves tools visible on phone-sized hosts. */
|
|
39
|
+
export const drawingEditorRecipe = {
|
|
40
|
+
maxCanvas: 400, minCanvas: 160, gap: 12, radius: 16, sizePreviewMs: 700,
|
|
41
|
+
brush: { min: 2, max: 32, step: 2, initial: 12 },
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=drawing-editor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drawing-editor.js","sourceRoot":"","sources":["../src/drawing-editor.ts"],"names":[],"mappings":"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","sourcesContent":["export const DRAWING_INK_COLORS = ['#333d4b', '#ffffff', '#e03131', '#f08c00', '#ffd43b', '#087f5b', '#3f66a5', '#7048e8', '#9c4668', '#f783ac', '#8d6e63', '#868e96'] as const;\n/** Default background. The person can change it; the chosen background is part of the saved photo. */\nexport const DRAWING_PAPER = '#fffaf2';\n/** Background presets: the default paper, light tints that keep ink readable, and one dark ground for light ink. */\nexport const DRAWING_BACKGROUND_COLORS = ['#fffaf2', '#ffffff', '#f1f3f5', '#ffe3e3', '#ffdeeb', '#fff3bf', '#d3f9d8', '#c5f6fa', '#d0ebff', '#e5dbff', '#333d4b'] as const;\n/**\n * An eraser stroke has no colour of its own: it paints whatever the background is when drawn, so changing the\n * background after erasing never leaves old-paper stripes (2026-10-25, background colour added).\n */\nexport type DrawingStroke = Readonly<{ width: number; points: readonly [number, number][] } & ({ color: string; erase?: never } | { erase: true; color?: never })>;\nexport function drawingStrokeColor(stroke: DrawingStroke, background: string): string {\n return stroke.erase ? background : stroke.color;\n}\n/** Something worth saving: an ink stroke, or a background other than the default paper. */\nexport function drawingHasContent(strokes: readonly DrawingStroke[], background: string): boolean {\n return background !== DRAWING_PAPER || strokes.some(stroke => !stroke.erase);\n}\nexport function drawingInkPath(stroke: DrawingStroke): string {\n return stroke.points.map(([x, y], i) => `${i ? 'L' : 'M'}${x.toFixed(1)},${y.toFixed(1)}`).join(' ') + (stroke.points.length === 1 ? ' l0.1,0.1' : '');\n}\n\nexport type DrawingHistory = Readonly<{\n past: readonly (readonly DrawingStroke[])[];\n present: readonly DrawingStroke[];\n future: readonly (readonly DrawingStroke[])[];\n}>;\nexport type DrawingAction = Readonly<{ type: 'add'; stroke: DrawingStroke }> | Readonly<{ type: 'undo' | 'redo' | 'clear' }>;\nexport const emptyDrawing: DrawingHistory = { past: [], present: [], future: [] };\n/** A stroke, including an eraser, is one undo step. Clearing can also be undone. */\nexport function drawingReducer(state: DrawingHistory, action: DrawingAction): DrawingHistory {\n if (action.type === 'undo') {\n const previous = state.past.at(-1);\n return previous ? { past: state.past.slice(0, -1), present: previous, future: [state.present, ...state.future] } : state;\n }\n if (action.type === 'redo') {\n const next = state.future[0];\n return next ? { past: [...state.past, state.present], present: next, future: state.future.slice(1) } : state;\n }\n if (action.type === 'clear' && !state.present.length) return state;\n return { past: [...state.past, state.present], present: action.type === 'add' ? [...state.present, action.stroke] : [], future: [] };\n}\n\n/**\n * One-row colour strip for the drawing toolbar: colours the person picked from the full picker this session come\n * first (newest first, at most four), then the presets. Recent colours are not stored; the drawing itself is.\n */\nexport function drawingQuickColors(recent: readonly string[]): readonly string[] {\n return [...new Set([...recent.slice(0, 4), ...DRAWING_INK_COLORS])];\n}\n\n/** Shared editor geometry; the 400px cap leaves tools visible on phone-sized hosts. */\nexport const drawingEditorRecipe = {\n maxCanvas: 400, minCanvas: 160, gap: 12, radius: 16, sizePreviewMs: 700,\n brush: { min: 2, max: 32, step: 2, initial: 12 },\n} as const;\nexport type DrawingImage = Readonly<{ base64: string; mimeType: 'image/png' | 'image/jpeg' }>;\nexport type DrawingEditorLabels = Readonly<{\n title: string; save: string; close: string; cancel: string; failed: string;\n pen: string; eraser: string; undo: string; redo: string; clear: string; width: string;\n moreColors: string; penColor: string; background: string; backgroundPresets: string;\n hex: string; hue: string; saturation: string; brightness: string; opacity: string; invalidColor: string;\n discardTitle: string; discardBody: string; discardConfirm: string;\n}>;\n/** Upload, account identity and navigation stay in the product. Reject on failure to retain the drawing. */\nexport type DrawingEditorProps = Readonly<{\n labels: DrawingEditorLabels;\n onSave(image: DrawingImage): Promise<void>;\n onCancel(): void;\n cropPreview?: 'circle' | 'none';\n safeAreaBottom?: number;\n testID?: string;\n}>;\n"]}
|
package/dist/timeline.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type TimelineDescriptor<Id extends string = string> = Readonly<{
|
|
|
33
33
|
}>;
|
|
34
34
|
export declare const timelineDefaults: {
|
|
35
35
|
readonly itemTone: "neutral";
|
|
36
|
+
readonly variant: "journal";
|
|
36
37
|
};
|
|
37
38
|
export type TimelineAccessibleNameInfo = Readonly<{
|
|
38
39
|
position: number;
|
|
@@ -67,6 +68,7 @@ export declare function validateTimelineDescriptor<Id extends string>(descriptor
|
|
|
67
68
|
*/
|
|
68
69
|
export declare function validateTimelineSelection(selectedId: unknown, onSelectedIdChange: unknown, options?: Readonly<{
|
|
69
70
|
hasActions: boolean;
|
|
71
|
+
variant?: "record" | "journal";
|
|
70
72
|
}>): void;
|
|
71
73
|
/**
|
|
72
74
|
* Keyboard target for a selectable Timeline (vertical listbox): ArrowDown/ArrowUp step one record, Home/End jump to
|
|
@@ -84,6 +86,11 @@ export declare function resolveTimelineDescriptor<Id extends string>(descriptor:
|
|
|
84
86
|
export declare const timelineRecipe: {
|
|
85
87
|
readonly slots: readonly ["root", "item", "dot", "connector", "content", "timestamp", "label", "description"];
|
|
86
88
|
readonly gap: 20;
|
|
89
|
+
readonly journal: {
|
|
90
|
+
readonly gap: 0;
|
|
91
|
+
readonly paddingBlock: 16;
|
|
92
|
+
readonly dotDiameter: 8;
|
|
93
|
+
};
|
|
87
94
|
readonly item: {
|
|
88
95
|
readonly padding: 12;
|
|
89
96
|
readonly emphasisBackground: Readonly<{
|
package/dist/timeline.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAMA;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;AAE5E,MAAM,MAAM,sBAAsB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACxE,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,MAAM,CAAC;IACd,0HAA0H;IAC1H,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,iFAAiF;IACjF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC,CAAC;AAEH,MAAM,MAAM,kBAAkB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACpE,KAAK,EAAE,SAAS,sBAAsB,CAAC,EAAE,CAAC,EAAE,CAAC;IAC7C;;;;OAIG;IACH,UAAU,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC;CACxB,CAAC,CAAC;AAEH,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"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"}
|
package/dist/timeline.js
CHANGED
|
@@ -3,6 +3,7 @@ import { semanticColors } from "./semantic-colors.js";
|
|
|
3
3
|
import { getCollectionNavigationIntent, getCollectionNavigationTarget } from "./collection.js";
|
|
4
4
|
export const timelineDefaults = {
|
|
5
5
|
itemTone: "neutral",
|
|
6
|
+
variant: "journal",
|
|
6
7
|
};
|
|
7
8
|
function assertNonEmpty(value, field) {
|
|
8
9
|
if (value.trim().length === 0) {
|
|
@@ -60,6 +61,9 @@ export function validateTimelineDescriptor(descriptor) {
|
|
|
60
61
|
* the passive Timeline.
|
|
61
62
|
*/
|
|
62
63
|
export function validateTimelineSelection(selectedId, onSelectedIdChange, options = { hasActions: false }) {
|
|
64
|
+
if (options.variant !== undefined && options.variant !== "record" && options.variant !== "journal") {
|
|
65
|
+
throw new TypeError("Unsupported Timeline variant");
|
|
66
|
+
}
|
|
63
67
|
if ((selectedId === undefined) !== (onSelectedIdChange === undefined)) {
|
|
64
68
|
throw new TypeError("Timeline selectedId and onSelectedIdChange must be supplied together");
|
|
65
69
|
}
|
|
@@ -125,6 +129,9 @@ export const timelineRecipe = {
|
|
|
125
129
|
"description",
|
|
126
130
|
],
|
|
127
131
|
gap: spacing.lg,
|
|
132
|
+
// 2026-10-27: the approved journey journal keeps the reading rail, without large selected cards.
|
|
133
|
+
// Passive histories keep every detail and command; selection adds disclosure without changing event semantics.
|
|
134
|
+
journal: { gap: 0, paddingBlock: spacing.md, dotDiameter: 8 },
|
|
128
135
|
// A record remains passive: emphasis highlights its history without implying progress.
|
|
129
136
|
item: {
|
|
130
137
|
padding: spacing.sm,
|
package/dist/timeline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,6BAA6B,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAC;AAsC/F,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,EAAE,SAAS;CACwC,CAAC;AAmC9D,SAAS,cAAc,CAAC,KAAa,EAAE,KAAa;IAClD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,SAAS,CAAC,YAAY,KAAK,oBAAoB,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,8BAA8B,CAC5C,IAAgC;IAEhC,cAAc,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC1E,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;IAChF,CAAC;IACD,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IACzC,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,cAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QAC/C,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS;YAAE,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;IAChG,CAAC;IACD,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACnC,cAAc,CAAC,IAAI,CAAC,WAAW,EAAE,kBAAkB,CAAC,CAAC;IACvD,CAAC;IACD,IACE,IAAI,CAAC,IAAI,KAAK,SAAS;QACvB,IAAI,CAAC,IAAI,KAAK,SAAS;QACvB,IAAI,CAAC,IAAI,KAAK,MAAM;QACpB,IAAI,CAAC,IAAI,KAAK,SAAS;QACvB,IAAI,CAAC,IAAI,KAAK,WAAW,EACzB,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,mCAAmC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAkC;IAElC,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,UAAU,CAAC,yCAAyC,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAM,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QACpC,8BAA8B,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,SAAS,CAAC,+BAA+B,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7G,MAAM,IAAI,UAAU,CAAC,mDAAmD,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC3G,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAmB,EACnB,kBAA2B,EAC3B,UAA6C,EAAE,UAAU,EAAE,KAAK,EAAE;IAElE,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,KAAK,CAAC,kBAAkB,KAAK,SAAS,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,SAAS,CAAC,sEAAsE,CAAC,CAAC;IAC9F,CAAC;IACD,IAAI,kBAAkB,KAAK,SAAS,IAAI,OAAO,kBAAkB,KAAK,UAAU,EAAE,CAAC;QACjF,MAAM,IAAI,SAAS,CAAC,gDAAgD,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,kBAAkB,KAAK,SAAS,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CAAC,mGAAmG,CAAC,CAAC;IAC3H,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACxC,KAA4C,EAC5C,SAAoB,EACpB,GAAW;IAEX,MAAM,MAAM,GAAG,6BAA6B,CAAC,GAA0D,CAAC,CAAC;IACzG,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,6BAA6B,CAClC,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAC3F,SAAS,EACT,MAAM,EACN,KAAK,CACN,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,UAAkC,EAClC,OAA+B;IAE/B,0BAA0B,CAAC,UAAU,CAAC,CAAC;IACvC,IAAI,OAAO,OAAO,CAAC,qBAAqB,KAAK,UAAU,EAAE,CAAC;QACxD,MAAM,IAAI,SAAS,CAAC,mDAAmD,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;IACtC,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC1C,MAAM,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAC;QAC3B,MAAM,cAAc,GAAG,OAAO,CAAC,qBAAqB,CAAC;YACnD,QAAQ;YACR,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QACH,IAAI,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7E,MAAM,IAAI,SAAS,CACjB,+DAA+D,CAChE,CAAC;QACJ,CAAC;QACD,OAAO;YACL,GAAG,IAAI;YACP,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,gBAAgB,CAAC,QAAQ;YAC5C,QAAQ;YACR,KAAK;YACL,cAAc;YACd,QAAQ,EAAE,UAAU,CAAC,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,UAAU,KAAK,IAAI,CAAC,EAAE;SACnF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE;QACL,MAAM;QACN,MAAM;QACN,KAAK;QACL,WAAW;QACX,SAAS;QACT,WAAW;QACX,OAAO;QACP,aAAa;KACL;IACV,GAAG,EAAE,OAAO,CAAC,EAAE;IACf,uFAAuF;IACvF,IAAI,EAAE;QACJ,OAAO,EAAE,OAAO,CAAC,EAAE;QACnB,kBAAkB,EAAE,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU;QAC3D;;;WAGG;QACH,QAAQ,EAAE;YACR,UAAU,EAAE,cAAc,CAAC,SAAS,CAAC,UAAU;YAC/C,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,MAAM;YACvC,WAAW,EAAE,MAAM,CAAC,OAAO;SAC5B;KACF;IACD,GAAG,EAAE;QACH,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,MAAM,CAAC,OAAO;QAC3B,KAAK,EAAE;YACL,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,SAAS,EAAE;YACjE,IAAI,EAAE;gBACJ,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM;gBAC3C,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU;aAC9C;YACD,OAAO,EAAE;gBACP,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM;gBAC9C,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU;aACjD;YACD,SAAS,EAAE;gBACT,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM;gBAChD,IAAI,EAAE,cAAc,CAAC,QAAQ,CAAC,SAAS,CAAC,UAAU;aACnD;SACF;KACF;IACD;;;OAGG;IACH,SAAS,EAAE;QACT,KAAK,EAAE,MAAM,CAAC,OAAO;QACrB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,OAAO;KACpC;IACD,SAAS,EAAE;QACT,WAAW,EAAE,SAAS;QACtB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,SAAS;KACxC;IACD,KAAK,EAAE;QACL,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,UAAU,CAAC,MAAM;QAC7B,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO;KACtC;IACD,WAAW,EAAE;QACX,WAAW,EAAE,MAAM;QACnB,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI;KACnC;CAwBF,CAAC","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { FontWeightValue, TextVariant } from \"./foundations.js\";\nimport { fontWeight, spacing, stroke } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport { getCollectionNavigationIntent, getCollectionNavigationTarget } from \"./collection.js\";\n\n/**\n * Timeline is a record of what already happened, not a position in a flow —\n * that is Steps' job (see docs/steps.md and the boundary note in\n * docs/timeline.md). Because there is no cursor, Timeline never derives a\n * status from position: every item is simply \"happened\", and the connector\n * between items carries no reached/unreached meaning. Ant Design's\n * alternating left/right layout is intentionally not reproduced — it is a\n * Web-only decoration with no equivalent in a single-direction native list;\n * see docs/timeline.md for the rationale.\n */\nexport type TimelineItemTone = \"neutral\" | \"info\" | \"success\" | \"attention\";\n\nexport type TimelineItemDescriptor<Id extends string = string> = Readonly<{\n id: Id;\n label: string;\n /** Product-formatted \"when\" copy, e.g. \"3회 초\" or \"2024-01-15\". Timeline never formats a clock, inning, or date itself. */\n timestamp?: string;\n /** Machine-readable date for the formatted timestamp; products retain the original instant. */\n dateTime?: string;\n /** Product-formatted supplementary detail, e.g. \"안타로 1루 진출\". */\n description?: string;\n tone?: TimelineItemTone;\n /** Passive emphasis for a notable record, not a progress cursor or selection. */\n emphasized?: boolean;\n}>;\n\nexport type TimelineDescriptor<Id extends string = string> = Readonly<{\n items: readonly TimelineItemDescriptor<Id>[];\n /**\n * Single selection of one record (2026-10-23): `undefined` keeps the passive record, `null` makes the list selectable\n * with nothing chosen yet. Selection is not a progress cursor — no status is derived from it. Diairy's journey log\n * rebuilt this with a `Button` tone toggle + `aria-pressed` per step (SELECTION forbids button-as-selection).\n */\n selectedId?: Id | null;\n}>;\n\nexport const timelineDefaults = {\n itemTone: \"neutral\",\n} as const satisfies Readonly<{ itemTone: TimelineItemTone }>;\n\nexport type TimelineAccessibleNameInfo = Readonly<{\n position: number;\n total: number;\n label: string;\n}>;\n\n/**\n * Products own the exact phrase order and counter-word grammar, same reason\n * Steps does not assemble its own accessible name (see docs/steps.md).\n */\nexport type ComposeTimelineAccessibleName = (\n info: TimelineAccessibleNameInfo,\n) => string;\n\nexport type ResolvedTimelineItemDescriptor<Id extends string = string> = Omit<\n TimelineItemDescriptor<Id>,\n \"tone\"\n> &\n Readonly<{\n tone: TimelineItemTone;\n /** 1-indexed so position and label both preserve reading order for renderers. */\n position: number;\n total: number;\n /** Order + label, for platforms without built-in list-position semantics. */\n accessibleName: string;\n /** True only for the record matching a selectable Timeline's `selectedId`. */\n selected: boolean;\n }>;\n\nexport type ResolveTimelineOptions = Readonly<{\n composeAccessibleName: ComposeTimelineAccessibleName;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Timeline ${field} must not be empty`);\n }\n}\n\nexport function validateTimelineItemDescriptor<Id extends string>(\n item: TimelineItemDescriptor<Id>,\n): void {\n assertNonEmpty(item.id, \"item id\");\n if (item.emphasized !== undefined && typeof item.emphasized !== \"boolean\") {\n throw new TypeError(\"Timeline item emphasized must be a boolean\");\n }\n if (item.id !== item.id.trim()) {\n throw new TypeError(\"Timeline item id must not start or end with whitespace\");\n }\n assertNonEmpty(item.label, \"item label\");\n if (item.timestamp !== undefined) {\n assertNonEmpty(item.timestamp, \"item timestamp\");\n }\n if (item.dateTime !== undefined) {\n assertNonEmpty(item.dateTime, \"item dateTime\");\n if (item.timestamp === undefined) throw new TypeError(\"Timeline dateTime requires timestamp\");\n }\n if (item.description !== undefined) {\n assertNonEmpty(item.description, \"item description\");\n }\n if (\n item.tone !== undefined &&\n item.tone !== \"neutral\" &&\n item.tone !== \"info\" &&\n item.tone !== \"success\" &&\n item.tone !== \"attention\"\n ) {\n throw new TypeError(`Unsupported Timeline item tone: ${String(item.tone)}`);\n }\n}\n\nexport function validateTimelineDescriptor<Id extends string>(\n descriptor: TimelineDescriptor<Id>,\n): void {\n if (descriptor.items.length === 0) {\n throw new RangeError(\"Timeline must contain at least one item\");\n }\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n validateTimelineItemDescriptor(item);\n if (ids.has(item.id)) {\n throw new TypeError(`Duplicate Timeline item id: ${item.id}`);\n }\n ids.add(item.id);\n }\n if (descriptor.selectedId !== undefined && descriptor.selectedId !== null && !ids.has(descriptor.selectedId)) {\n throw new RangeError(`Timeline selectedId does not match any item id: ${String(descriptor.selectedId)}`);\n }\n}\n\n/**\n * Selection is a pair: a controlled `selectedId` (null for none) and the change callback, or neither. A selectable\n * record is one target (Web option, Native selected button), so it cannot also host `renderActions` commands —\n * nested controls inside an option are not operable by assistive tech. Products that need a per-record command keep\n * the passive Timeline.\n */\nexport function validateTimelineSelection(\n selectedId: unknown,\n onSelectedIdChange: unknown,\n options: Readonly<{ hasActions: boolean }> = { hasActions: false },\n): void {\n if ((selectedId === undefined) !== (onSelectedIdChange === undefined)) {\n throw new TypeError(\"Timeline selectedId and onSelectedIdChange must be supplied together\");\n }\n if (onSelectedIdChange !== undefined && typeof onSelectedIdChange !== \"function\") {\n throw new TypeError(\"Timeline onSelectedIdChange must be a function\");\n }\n if (onSelectedIdChange !== undefined && options.hasActions) {\n throw new TypeError(\"A selectable Timeline cannot render per-record actions; the record itself is the selection target\");\n }\n}\n\n/**\n * Keyboard target for a selectable Timeline (vertical listbox): ArrowDown/ArrowUp step one record, Home/End jump to\n * the ends, and the ends do not wrap — a history has a first and a last record. Selection follows focus, as in the\n * single-select listbox pattern, because choosing a record only changes what the product shows next to it.\n * Returns undefined for keys Timeline does not own. Reuses the shared collection navigation math.\n */\nexport function getTimelineSelectionTarget<Id extends string>(\n items: readonly TimelineItemDescriptor<Id>[],\n currentId: Id | null,\n key: string,\n): Id | undefined {\n const intent = getCollectionNavigationIntent(key as Parameters<typeof getCollectionNavigationIntent>[0]);\n if (!intent) return undefined;\n return getCollectionNavigationTarget(\n { items: items.map((item) => ({ id: item.id, label: item.label, textValue: item.label })) },\n currentId,\n intent,\n false,\n );\n}\n\n/**\n * Attaches order-preserving accessible names to an already-ordered item list.\n * Unlike Steps, no status is derived from position — every item already\n * happened, so this only adds order and the resolved tone default.\n */\nexport function resolveTimelineDescriptor<Id extends string>(\n descriptor: TimelineDescriptor<Id>,\n options: ResolveTimelineOptions,\n): readonly ResolvedTimelineItemDescriptor<Id>[] {\n validateTimelineDescriptor(descriptor);\n if (typeof options.composeAccessibleName !== \"function\") {\n throw new TypeError(\"Timeline composeAccessibleName must be a function\");\n }\n\n const total = descriptor.items.length;\n return descriptor.items.map((item, index) => {\n const position = index + 1;\n const accessibleName = options.composeAccessibleName({\n position,\n total,\n label: item.label,\n });\n if (typeof accessibleName !== \"string\" || accessibleName.trim().length === 0) {\n throw new TypeError(\n \"Timeline composeAccessibleName must return a non-empty string\",\n );\n }\n return {\n ...item,\n tone: item.tone ?? timelineDefaults.itemTone,\n position,\n total,\n accessibleName,\n selected: descriptor.selectedId !== undefined && descriptor.selectedId === item.id,\n };\n });\n}\n\nexport const timelineRecipe = {\n slots: [\n \"root\",\n \"item\",\n \"dot\",\n \"connector\",\n \"content\",\n \"timestamp\",\n \"label\",\n \"description\",\n ] as const,\n gap: spacing.lg,\n // A record remains passive: emphasis highlights its history without implying progress.\n item: {\n padding: spacing.sm,\n emphasisBackground: semanticColors.feedback.info.background,\n /**\n * Selected record (selectable Timeline): the neutral persistent-selection surface and ring shared with ListRow,\n * not brand fill (theme-palette.md 선택 상태 색상 기준). Selection outranks passive emphasis on the same record.\n */\n selected: {\n background: semanticColors.selection.background,\n border: semanticColors.selection.border,\n borderWidth: stroke.default,\n },\n },\n dot: {\n diameter: 10,\n borderWidth: stroke.default,\n tones: {\n neutral: { border: null, fill: semanticColors.content.secondary },\n info: {\n border: semanticColors.feedback.info.border,\n fill: semanticColors.feedback.info.foreground,\n },\n success: {\n border: semanticColors.feedback.success.border,\n fill: semanticColors.feedback.success.foreground,\n },\n attention: {\n border: semanticColors.feedback.attention.border,\n fill: semanticColors.feedback.attention.foreground,\n },\n },\n },\n /**\n * A single tone, unlike stepsRecipe.connector's reached/unreached pair —\n * Timeline has no cursor, so no segment is \"not yet reached\".\n */\n connector: {\n width: stroke.default,\n tone: semanticColors.border.default,\n },\n timestamp: {\n textVariant: \"caption\",\n color: semanticColors.content.secondary,\n },\n label: {\n textVariant: \"body\",\n fontWeight: fontWeight.medium,\n color: semanticColors.content.primary,\n },\n description: {\n textVariant: \"body\",\n color: semanticColors.content.body,\n },\n} as const satisfies {\n slots: readonly string[];\n gap: number;\n item: {\n padding: number;\n emphasisBackground: ColorReference;\n selected: { background: ColorReference; border: ColorReference; borderWidth: number };\n };\n dot: {\n diameter: number;\n borderWidth: number;\n tones: Record<\n TimelineItemTone,\n { border: ColorReference | null; fill: ColorReference }\n >;\n };\n connector: {\n width: number;\n tone: ColorReference;\n };\n timestamp: { textVariant: TextVariant; color: ColorReference };\n label: { textVariant: TextVariant; fontWeight: FontWeightValue; color: ColorReference };\n description: { textVariant: TextVariant; color: ColorReference };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../src/timeline.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ColorReference } from \"./color-references.js\";\nimport type { FontWeightValue, TextVariant } from \"./foundations.js\";\nimport { fontWeight, spacing, stroke } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport { getCollectionNavigationIntent, getCollectionNavigationTarget } from \"./collection.js\";\n\n/**\n * Timeline is a record of what already happened, not a position in a flow —\n * that is Steps' job (see docs/steps.md and the boundary note in\n * docs/timeline.md). Because there is no cursor, Timeline never derives a\n * status from position: every item is simply \"happened\", and the connector\n * between items carries no reached/unreached meaning. Ant Design's\n * alternating left/right layout is intentionally not reproduced — it is a\n * Web-only decoration with no equivalent in a single-direction native list;\n * see docs/timeline.md for the rationale.\n */\nexport type TimelineItemTone = \"neutral\" | \"info\" | \"success\" | \"attention\";\n\nexport type TimelineItemDescriptor<Id extends string = string> = Readonly<{\n id: Id;\n label: string;\n /** Product-formatted \"when\" copy, e.g. \"3회 초\" or \"2024-01-15\". Timeline never formats a clock, inning, or date itself. */\n timestamp?: string;\n /** Machine-readable date for the formatted timestamp; products retain the original instant. */\n dateTime?: string;\n /** Product-formatted supplementary detail, e.g. \"안타로 1루 진출\". */\n description?: string;\n tone?: TimelineItemTone;\n /** Passive emphasis for a notable record, not a progress cursor or selection. */\n emphasized?: boolean;\n}>;\n\nexport type TimelineDescriptor<Id extends string = string> = Readonly<{\n items: readonly TimelineItemDescriptor<Id>[];\n /**\n * Single selection of one record (2026-10-23): `undefined` keeps the passive record, `null` makes the list selectable\n * with nothing chosen yet. Selection is not a progress cursor — no status is derived from it. Diairy's journey log\n * rebuilt this with a `Button` tone toggle + `aria-pressed` per step (SELECTION forbids button-as-selection).\n */\n selectedId?: Id | null;\n}>;\n\nexport const timelineDefaults = {\n itemTone: \"neutral\",\n variant: \"journal\",\n} as const satisfies Readonly<{ itemTone: TimelineItemTone; variant: \"record\" | \"journal\" }>;\n\nexport type TimelineAccessibleNameInfo = Readonly<{\n position: number;\n total: number;\n label: string;\n}>;\n\n/**\n * Products own the exact phrase order and counter-word grammar, same reason\n * Steps does not assemble its own accessible name (see docs/steps.md).\n */\nexport type ComposeTimelineAccessibleName = (\n info: TimelineAccessibleNameInfo,\n) => string;\n\nexport type ResolvedTimelineItemDescriptor<Id extends string = string> = Omit<\n TimelineItemDescriptor<Id>,\n \"tone\"\n> &\n Readonly<{\n tone: TimelineItemTone;\n /** 1-indexed so position and label both preserve reading order for renderers. */\n position: number;\n total: number;\n /** Order + label, for platforms without built-in list-position semantics. */\n accessibleName: string;\n /** True only for the record matching a selectable Timeline's `selectedId`. */\n selected: boolean;\n }>;\n\nexport type ResolveTimelineOptions = Readonly<{\n composeAccessibleName: ComposeTimelineAccessibleName;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (value.trim().length === 0) {\n throw new TypeError(`Timeline ${field} must not be empty`);\n }\n}\n\nexport function validateTimelineItemDescriptor<Id extends string>(\n item: TimelineItemDescriptor<Id>,\n): void {\n assertNonEmpty(item.id, \"item id\");\n if (item.emphasized !== undefined && typeof item.emphasized !== \"boolean\") {\n throw new TypeError(\"Timeline item emphasized must be a boolean\");\n }\n if (item.id !== item.id.trim()) {\n throw new TypeError(\"Timeline item id must not start or end with whitespace\");\n }\n assertNonEmpty(item.label, \"item label\");\n if (item.timestamp !== undefined) {\n assertNonEmpty(item.timestamp, \"item timestamp\");\n }\n if (item.dateTime !== undefined) {\n assertNonEmpty(item.dateTime, \"item dateTime\");\n if (item.timestamp === undefined) throw new TypeError(\"Timeline dateTime requires timestamp\");\n }\n if (item.description !== undefined) {\n assertNonEmpty(item.description, \"item description\");\n }\n if (\n item.tone !== undefined &&\n item.tone !== \"neutral\" &&\n item.tone !== \"info\" &&\n item.tone !== \"success\" &&\n item.tone !== \"attention\"\n ) {\n throw new TypeError(`Unsupported Timeline item tone: ${String(item.tone)}`);\n }\n}\n\nexport function validateTimelineDescriptor<Id extends string>(\n descriptor: TimelineDescriptor<Id>,\n): void {\n if (descriptor.items.length === 0) {\n throw new RangeError(\"Timeline must contain at least one item\");\n }\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n validateTimelineItemDescriptor(item);\n if (ids.has(item.id)) {\n throw new TypeError(`Duplicate Timeline item id: ${item.id}`);\n }\n ids.add(item.id);\n }\n if (descriptor.selectedId !== undefined && descriptor.selectedId !== null && !ids.has(descriptor.selectedId)) {\n throw new RangeError(`Timeline selectedId does not match any item id: ${String(descriptor.selectedId)}`);\n }\n}\n\n/**\n * Selection is a pair: a controlled `selectedId` (null for none) and the change callback, or neither. A selectable\n * record is one target (Web option, Native selected button), so it cannot also host `renderActions` commands —\n * nested controls inside an option are not operable by assistive tech. Products that need a per-record command keep\n * the passive Timeline.\n */\nexport function validateTimelineSelection(\n selectedId: unknown,\n onSelectedIdChange: unknown,\n options: Readonly<{ hasActions: boolean; variant?: \"record\" | \"journal\" }> = { hasActions: false },\n): void {\n if (options.variant !== undefined && options.variant !== \"record\" && options.variant !== \"journal\") {\n throw new TypeError(\"Unsupported Timeline variant\");\n }\n if ((selectedId === undefined) !== (onSelectedIdChange === undefined)) {\n throw new TypeError(\"Timeline selectedId and onSelectedIdChange must be supplied together\");\n }\n if (onSelectedIdChange !== undefined && typeof onSelectedIdChange !== \"function\") {\n throw new TypeError(\"Timeline onSelectedIdChange must be a function\");\n }\n if (onSelectedIdChange !== undefined && options.hasActions) {\n throw new TypeError(\"A selectable Timeline cannot render per-record actions; the record itself is the selection target\");\n }\n}\n\n/**\n * Keyboard target for a selectable Timeline (vertical listbox): ArrowDown/ArrowUp step one record, Home/End jump to\n * the ends, and the ends do not wrap — a history has a first and a last record. Selection follows focus, as in the\n * single-select listbox pattern, because choosing a record only changes what the product shows next to it.\n * Returns undefined for keys Timeline does not own. Reuses the shared collection navigation math.\n */\nexport function getTimelineSelectionTarget<Id extends string>(\n items: readonly TimelineItemDescriptor<Id>[],\n currentId: Id | null,\n key: string,\n): Id | undefined {\n const intent = getCollectionNavigationIntent(key as Parameters<typeof getCollectionNavigationIntent>[0]);\n if (!intent) return undefined;\n return getCollectionNavigationTarget(\n { items: items.map((item) => ({ id: item.id, label: item.label, textValue: item.label })) },\n currentId,\n intent,\n false,\n );\n}\n\n/**\n * Attaches order-preserving accessible names to an already-ordered item list.\n * Unlike Steps, no status is derived from position — every item already\n * happened, so this only adds order and the resolved tone default.\n */\nexport function resolveTimelineDescriptor<Id extends string>(\n descriptor: TimelineDescriptor<Id>,\n options: ResolveTimelineOptions,\n): readonly ResolvedTimelineItemDescriptor<Id>[] {\n validateTimelineDescriptor(descriptor);\n if (typeof options.composeAccessibleName !== \"function\") {\n throw new TypeError(\"Timeline composeAccessibleName must be a function\");\n }\n\n const total = descriptor.items.length;\n return descriptor.items.map((item, index) => {\n const position = index + 1;\n const accessibleName = options.composeAccessibleName({\n position,\n total,\n label: item.label,\n });\n if (typeof accessibleName !== \"string\" || accessibleName.trim().length === 0) {\n throw new TypeError(\n \"Timeline composeAccessibleName must return a non-empty string\",\n );\n }\n return {\n ...item,\n tone: item.tone ?? timelineDefaults.itemTone,\n position,\n total,\n accessibleName,\n selected: descriptor.selectedId !== undefined && descriptor.selectedId === item.id,\n };\n });\n}\n\nexport const timelineRecipe = {\n slots: [\n \"root\",\n \"item\",\n \"dot\",\n \"connector\",\n \"content\",\n \"timestamp\",\n \"label\",\n \"description\",\n ] as const,\n gap: spacing.lg,\n // 2026-10-27: the approved journey journal keeps the reading rail, without large selected cards.\n // Passive histories keep every detail and command; selection adds disclosure without changing event semantics.\n journal: { gap: 0, paddingBlock: spacing.md, dotDiameter: 8 },\n // A record remains passive: emphasis highlights its history without implying progress.\n item: {\n padding: spacing.sm,\n emphasisBackground: semanticColors.feedback.info.background,\n /**\n * Selected record (selectable Timeline): the neutral persistent-selection surface and ring shared with ListRow,\n * not brand fill (theme-palette.md 선택 상태 색상 기준). Selection outranks passive emphasis on the same record.\n */\n selected: {\n background: semanticColors.selection.background,\n border: semanticColors.selection.border,\n borderWidth: stroke.default,\n },\n },\n dot: {\n diameter: 10,\n borderWidth: stroke.default,\n tones: {\n neutral: { border: null, fill: semanticColors.content.secondary },\n info: {\n border: semanticColors.feedback.info.border,\n fill: semanticColors.feedback.info.foreground,\n },\n success: {\n border: semanticColors.feedback.success.border,\n fill: semanticColors.feedback.success.foreground,\n },\n attention: {\n border: semanticColors.feedback.attention.border,\n fill: semanticColors.feedback.attention.foreground,\n },\n },\n },\n /**\n * A single tone, unlike stepsRecipe.connector's reached/unreached pair —\n * Timeline has no cursor, so no segment is \"not yet reached\".\n */\n connector: {\n width: stroke.default,\n tone: semanticColors.border.default,\n },\n timestamp: {\n textVariant: \"caption\",\n color: semanticColors.content.secondary,\n },\n label: {\n textVariant: \"body\",\n fontWeight: fontWeight.medium,\n color: semanticColors.content.primary,\n },\n description: {\n textVariant: \"body\",\n color: semanticColors.content.body,\n },\n} as const satisfies {\n slots: readonly string[];\n gap: number;\n journal: { gap: number; paddingBlock: number; dotDiameter: number };\n item: {\n padding: number;\n emphasisBackground: ColorReference;\n selected: { background: ColorReference; border: ColorReference; borderWidth: number };\n };\n dot: {\n diameter: number;\n borderWidth: number;\n tones: Record<\n TimelineItemTone,\n { border: ColorReference | null; fill: ColorReference }\n >;\n };\n connector: {\n width: number;\n tone: ColorReference;\n };\n timestamp: { textVariant: TextVariant; color: ColorReference };\n label: { textVariant: TextVariant; fontWeight: FontWeightValue; color: ColorReference };\n description: { textVariant: TextVariant; color: ColorReference };\n};\n"]}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/dist/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAiB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,QAAiB,CAAC","sourcesContent":["/** Package release shown by documentation surfaces. Kept in sync by a test. */\nexport const designSystemVersion = \"1.49.0\" as const;\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# 손그림 편집기 계약
|
|
2
|
+
|
|
3
|
+
2026-10-27 사용자 요청으로 다에리·스핀트의 동일한 그림 편집기를 공통 API로 옮겼다.
|
|
4
|
+
`DrawingEditor`는 `EditorScreen`·`ColorPicker`·`Slider`를 합성하는 beta 컴포넌트다.
|
|
5
|
+
|
|
6
|
+
순수 이력·선·지우개·배경·팔레트·배치는 `src/drawing-editor.ts`가 소유한다. Web pointer capture와 Native responder,
|
|
7
|
+
SVG/Canvas 이미지 추출은 각 renderer에 남는다. 제품 계정·업로드·저장 형식 제한·성공 후 탐색은 포함하지 않는다.
|
|
8
|
+
|
|
9
|
+
프로필 사진은 `cropPreview="circle"`을 전달한다. 기본 사각 캔버스와 원형 미리보기 모두 실제 출력에는 오버레이를 넣지 않는다.
|
|
10
|
+
저장 실패는 그림을 보존하며 같은 초안으로 다시 시도한다. 한 획을 하나의 이력 단계로 취급하고 새로운 획은 redo 분기를 없앤다.
|
|
11
|
+
펜과 지우개의 실제 굵기는 같은 슬라이더 값이며 지우개는 항상 현재 배경색을 따른다.
|
|
12
|
+
|
|
13
|
+
사용법과 소비 이관은 [DrawingEditor 지침](usage/components/drawing-editor.md)을 따른다. 미게시 개발 후보이며
|
|
14
|
+
구현·표면 테스트·제품 채택과 패키지 게시·실기기 QA는 각각 별도 상태다.
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Component maturity and evidence manifest
|
|
2
2
|
|
|
3
|
-
> Generated from `@hjmds/design-contracts` 1.
|
|
3
|
+
> Generated from `@hjmds/design-contracts` 1.49.0. Do not edit this file directly; run `pnpm contracts:sync`.
|
|
4
4
|
|
|
5
5
|
This document is the human-readable projection of the same catalog and Showcase manifest consumed by product CI.
|
|
6
6
|
|
|
7
|
-
- Contract: stable 131
|
|
8
|
-
- Web renderer: stable 131
|
|
9
|
-
- Native renderer: stable 114 · unsupported 17
|
|
7
|
+
- Contract: stable 131 · beta 1
|
|
8
|
+
- Web renderer: stable 131 · beta 1
|
|
9
|
+
- Native renderer: stable 114 · beta 1 · unsupported 17
|
|
10
10
|
|
|
11
11
|
| Component | Canonical story ID | Contract | Web | Native | Documentation | Required evidence |
|
|
12
12
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
@@ -54,6 +54,7 @@ This document is the human-readable projection of the same catalog and Showcase
|
|
|
54
54
|
| TimePicker | `input/time-picker` | stable | stable | stable | [authored](../time-picker.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions |
|
|
55
55
|
| DatePicker | `input/date-picker` | stable | stable | stable | [authored](../date-picker.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions |
|
|
56
56
|
| DateRangePicker | `input/date-range-picker` | stable | stable | stable | generated only | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, large-text, rtl, reduced-motion, accessibility, native-actions |
|
|
57
|
+
| DrawingEditor | `input/drawing-editor` | beta | beta | beta | [authored](../drawing-editor.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
57
58
|
| ColorPicker | `input/color-picker` | stable | stable | stable | [authored](../color-picker.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility |
|
|
58
59
|
| FilePicker | `input/file-picker` | stable | stable | stable | [authored](../file-picker.md) | contract: contract; web: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions |
|
|
59
60
|
| Form | `input/form` | stable | stable | stable | [authored](../form.md) | contract: contract; web: default, dark, large-text, rtl, reduced-motion, accessibility, keyboard; native: default, dark, large-text, rtl, reduced-motion, accessibility, native-actions |
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"designSystemVersion": "1.
|
|
3
|
+
"designSystemVersion": "1.49.0",
|
|
4
4
|
"source": "packages/design-contracts/docs/generated/showcase-manifest.json",
|
|
5
5
|
"surfaces": {
|
|
6
6
|
"web": {
|
|
7
7
|
"packageName": "@hjmds/react",
|
|
8
|
-
"packageVersion": "1.
|
|
9
|
-
"activeComponents":
|
|
10
|
-
"claimedComponents":
|
|
11
|
-
"completeScenarioComponents":
|
|
8
|
+
"packageVersion": "1.49.0",
|
|
9
|
+
"activeComponents": 132,
|
|
10
|
+
"claimedComponents": 132,
|
|
11
|
+
"completeScenarioComponents": 131,
|
|
12
12
|
"components": [
|
|
13
13
|
{
|
|
14
14
|
"componentId": "text",
|
|
@@ -2417,6 +2417,56 @@
|
|
|
2417
2417
|
],
|
|
2418
2418
|
"missingScenarios": []
|
|
2419
2419
|
},
|
|
2420
|
+
{
|
|
2421
|
+
"componentId": "drawing-editor",
|
|
2422
|
+
"name": "DrawingEditor",
|
|
2423
|
+
"status": "beta",
|
|
2424
|
+
"claimed": true,
|
|
2425
|
+
"subpath": "./drawing-editor",
|
|
2426
|
+
"exportNames": [
|
|
2427
|
+
"DrawingEditor"
|
|
2428
|
+
],
|
|
2429
|
+
"proofs": [
|
|
2430
|
+
{
|
|
2431
|
+
"scenarios": [
|
|
2432
|
+
"default"
|
|
2433
|
+
],
|
|
2434
|
+
"file": "test/default-render.ssr.test.tsx",
|
|
2435
|
+
"caseId": "drawing-editor"
|
|
2436
|
+
},
|
|
2437
|
+
{
|
|
2438
|
+
"scenarios": [
|
|
2439
|
+
"dark",
|
|
2440
|
+
"long-copy",
|
|
2441
|
+
"large-text",
|
|
2442
|
+
"rtl",
|
|
2443
|
+
"reduced-motion",
|
|
2444
|
+
"accessibility"
|
|
2445
|
+
],
|
|
2446
|
+
"file": "test/scenario-matrix.browser.test.tsx",
|
|
2447
|
+
"caseId": "drawing-editor"
|
|
2448
|
+
}
|
|
2449
|
+
],
|
|
2450
|
+
"requiredScenarios": [
|
|
2451
|
+
"default",
|
|
2452
|
+
"dark",
|
|
2453
|
+
"long-copy",
|
|
2454
|
+
"large-text",
|
|
2455
|
+
"rtl",
|
|
2456
|
+
"reduced-motion",
|
|
2457
|
+
"accessibility"
|
|
2458
|
+
],
|
|
2459
|
+
"claimedScenarios": [
|
|
2460
|
+
"default",
|
|
2461
|
+
"dark",
|
|
2462
|
+
"long-copy",
|
|
2463
|
+
"large-text",
|
|
2464
|
+
"rtl",
|
|
2465
|
+
"reduced-motion",
|
|
2466
|
+
"accessibility"
|
|
2467
|
+
],
|
|
2468
|
+
"missingScenarios": []
|
|
2469
|
+
},
|
|
2420
2470
|
{
|
|
2421
2471
|
"componentId": "color-picker",
|
|
2422
2472
|
"name": "ColorPicker",
|
|
@@ -7064,10 +7114,10 @@
|
|
|
7064
7114
|
},
|
|
7065
7115
|
"native": {
|
|
7066
7116
|
"packageName": "@hjmds/react-native",
|
|
7067
|
-
"packageVersion": "1.
|
|
7068
|
-
"activeComponents":
|
|
7069
|
-
"claimedComponents":
|
|
7070
|
-
"completeScenarioComponents":
|
|
7117
|
+
"packageVersion": "1.49.0",
|
|
7118
|
+
"activeComponents": 115,
|
|
7119
|
+
"claimedComponents": 115,
|
|
7120
|
+
"completeScenarioComponents": 112,
|
|
7071
7121
|
"components": [
|
|
7072
7122
|
{
|
|
7073
7123
|
"componentId": "text",
|
|
@@ -9355,6 +9405,56 @@
|
|
|
9355
9405
|
],
|
|
9356
9406
|
"missingScenarios": []
|
|
9357
9407
|
},
|
|
9408
|
+
{
|
|
9409
|
+
"componentId": "drawing-editor",
|
|
9410
|
+
"name": "DrawingEditor",
|
|
9411
|
+
"status": "beta",
|
|
9412
|
+
"claimed": true,
|
|
9413
|
+
"subpath": "./drawing-editor",
|
|
9414
|
+
"exportNames": [
|
|
9415
|
+
"DrawingEditor"
|
|
9416
|
+
],
|
|
9417
|
+
"proofs": [
|
|
9418
|
+
{
|
|
9419
|
+
"scenarios": [
|
|
9420
|
+
"default"
|
|
9421
|
+
],
|
|
9422
|
+
"file": "test/default-render.test.tsx",
|
|
9423
|
+
"caseId": "drawing-editor"
|
|
9424
|
+
},
|
|
9425
|
+
{
|
|
9426
|
+
"scenarios": [
|
|
9427
|
+
"dark",
|
|
9428
|
+
"long-copy",
|
|
9429
|
+
"large-text",
|
|
9430
|
+
"rtl",
|
|
9431
|
+
"reduced-motion",
|
|
9432
|
+
"accessibility"
|
|
9433
|
+
],
|
|
9434
|
+
"file": "test/scenario-matrix.test.tsx",
|
|
9435
|
+
"caseId": "drawing-editor"
|
|
9436
|
+
}
|
|
9437
|
+
],
|
|
9438
|
+
"requiredScenarios": [
|
|
9439
|
+
"default",
|
|
9440
|
+
"dark",
|
|
9441
|
+
"long-copy",
|
|
9442
|
+
"large-text",
|
|
9443
|
+
"rtl",
|
|
9444
|
+
"reduced-motion",
|
|
9445
|
+
"accessibility"
|
|
9446
|
+
],
|
|
9447
|
+
"claimedScenarios": [
|
|
9448
|
+
"default",
|
|
9449
|
+
"dark",
|
|
9450
|
+
"long-copy",
|
|
9451
|
+
"large-text",
|
|
9452
|
+
"rtl",
|
|
9453
|
+
"reduced-motion",
|
|
9454
|
+
"accessibility"
|
|
9455
|
+
],
|
|
9456
|
+
"missingScenarios": []
|
|
9457
|
+
},
|
|
9358
9458
|
{
|
|
9359
9459
|
"componentId": "color-picker",
|
|
9360
9460
|
"name": "ColorPicker",
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Renderer evidence coverage
|
|
2
2
|
|
|
3
|
-
> Generated for HJM 1.
|
|
3
|
+
> Generated for HJM 1.49.0. Do not edit directly; run `pnpm evidence:sync`.
|
|
4
4
|
|
|
5
5
|
This projection joins the canonical surface maturity manifest with first-party renderer claims. Missing scenarios are explicit beta promotion debt; stable surfaces are blocked by CI until none remain.
|
|
6
6
|
|
|
7
|
-
- web:
|
|
8
|
-
- native:
|
|
7
|
+
- web: 132/132 active implementations; 131/132 required scenario sets
|
|
8
|
+
- native: 115/115 active implementations; 112/115 required scenario sets
|
|
9
9
|
|
|
10
10
|
| Component | Surface | Maturity | Renderer package | Export | Claimed scenarios | Missing required scenarios | Executable proofs |
|
|
11
11
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
@@ -53,6 +53,7 @@ This projection joins the canonical surface maturity manifest with first-party r
|
|
|
53
53
|
| TimePicker | web | stable | @hjmds/react | ./time-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#time-picker, test/scenario-matrix.browser.test.tsx#time-picker, test/time-picker.browser.test.tsx#time-picker |
|
|
54
54
|
| DatePicker | web | stable | @hjmds/react | ./date-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#date-picker, test/scenario-matrix.browser.test.tsx#date-picker, test/stable-core.browser.test.tsx#date-picker |
|
|
55
55
|
| DateRangePicker | web | stable | @hjmds/react | ./date-range | default, dark, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#date-range-picker, test/scenario-matrix.browser.test.tsx#date-range-picker, test/date-range.keyboard.browser.test.tsx#date-range-picker |
|
|
56
|
+
| DrawingEditor | web | beta | @hjmds/react | ./drawing-editor | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility | none | test/default-render.ssr.test.tsx#drawing-editor, test/scenario-matrix.browser.test.tsx#drawing-editor |
|
|
56
57
|
| ColorPicker | web | stable | @hjmds/react | ./color-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#color-picker, test/scenario-matrix.browser.test.tsx#color-picker, test/web-additions.browser.test.tsx#color-picker |
|
|
57
58
|
| FilePicker | web | stable | @hjmds/react | ./file-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#file-picker, test/scenario-matrix.browser.test.tsx#file-picker, test/file-picker.keyboard.browser.test.tsx#file-picker |
|
|
58
59
|
| Form | web | stable | @hjmds/react | ./forms | default, dark, large-text, rtl, reduced-motion, accessibility, keyboard | none | test/default-render.ssr.test.tsx#form, test/scenario-matrix.browser.test.tsx#form, test/form.keyboard.browser.test.tsx#form |
|
|
@@ -182,6 +183,7 @@ This projection joins the canonical surface maturity manifest with first-party r
|
|
|
182
183
|
| TimePicker | native | stable | @hjmds/react-native | ./time-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions | none | test/default-render.test.tsx#time-picker, test/scenario-matrix.test.tsx#time-picker, test/time-picker.test.tsx#time-picker |
|
|
183
184
|
| DatePicker | native | stable | @hjmds/react-native | ./date-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions | none | test/default-render.test.tsx#date-picker, test/scenario-matrix.test.tsx#date-picker, test/stable-core.test.tsx#date-picker |
|
|
184
185
|
| DateRangePicker | native | stable | @hjmds/react-native | ./date-range | default, dark, large-text, rtl, reduced-motion, accessibility, native-actions | none | test/default-render.test.tsx#date-range-picker, test/scenario-matrix.test.tsx#date-range-picker, test/date-range-actions.test.tsx#date-range-picker |
|
|
186
|
+
| DrawingEditor | native | beta | @hjmds/react-native | ./drawing-editor | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility | none | test/default-render.test.tsx#drawing-editor, test/scenario-matrix.test.tsx#drawing-editor |
|
|
185
187
|
| ColorPicker | native | stable | @hjmds/react-native | ./color-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility | none | test/default-render.test.tsx#color-picker, test/scenario-matrix.test.tsx#color-picker |
|
|
186
188
|
| FilePicker | native | stable | @hjmds/react-native | ./file-picker | default, dark, long-copy, large-text, rtl, reduced-motion, accessibility, native-actions | none | test/default-render.test.tsx#file-picker, test/scenario-matrix.test.tsx#file-picker, test/file-picker-host-action.test.tsx#file-picker |
|
|
187
189
|
| Form | native | stable | @hjmds/react-native | ./forms | default, dark, large-text, rtl, reduced-motion, accessibility, native-actions | none | test/default-render.test.tsx#form, test/scenario-matrix.test.tsx#form, test/form.interaction.test.tsx#form |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
|
-
"designSystemVersion": "1.
|
|
3
|
+
"designSystemVersion": "1.49.0",
|
|
4
4
|
"packageName": "@hjmds/design-contracts",
|
|
5
5
|
"components": [
|
|
6
6
|
{
|
|
@@ -2289,6 +2289,57 @@
|
|
|
2289
2289
|
"authored": null
|
|
2290
2290
|
}
|
|
2291
2291
|
},
|
|
2292
|
+
{
|
|
2293
|
+
"id": "drawing-editor",
|
|
2294
|
+
"storyId": "input/drawing-editor",
|
|
2295
|
+
"name": "DrawingEditor",
|
|
2296
|
+
"label": "손그림 편집기",
|
|
2297
|
+
"companions": [],
|
|
2298
|
+
"extensions": [],
|
|
2299
|
+
"category": "input",
|
|
2300
|
+
"platform": "adaptive",
|
|
2301
|
+
"contractStatus": "beta",
|
|
2302
|
+
"surfaces": {
|
|
2303
|
+
"web": "beta",
|
|
2304
|
+
"native": "beta"
|
|
2305
|
+
},
|
|
2306
|
+
"requirements": [
|
|
2307
|
+
{
|
|
2308
|
+
"surface": "contract",
|
|
2309
|
+
"scenarios": [
|
|
2310
|
+
"contract"
|
|
2311
|
+
]
|
|
2312
|
+
},
|
|
2313
|
+
{
|
|
2314
|
+
"surface": "web",
|
|
2315
|
+
"scenarios": [
|
|
2316
|
+
"default",
|
|
2317
|
+
"dark",
|
|
2318
|
+
"long-copy",
|
|
2319
|
+
"large-text",
|
|
2320
|
+
"rtl",
|
|
2321
|
+
"reduced-motion",
|
|
2322
|
+
"accessibility"
|
|
2323
|
+
]
|
|
2324
|
+
},
|
|
2325
|
+
{
|
|
2326
|
+
"surface": "native",
|
|
2327
|
+
"scenarios": [
|
|
2328
|
+
"default",
|
|
2329
|
+
"dark",
|
|
2330
|
+
"long-copy",
|
|
2331
|
+
"large-text",
|
|
2332
|
+
"rtl",
|
|
2333
|
+
"reduced-motion",
|
|
2334
|
+
"accessibility"
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
2337
|
+
],
|
|
2338
|
+
"documentation": {
|
|
2339
|
+
"generated": "docs/generated/component-maturity.md",
|
|
2340
|
+
"authored": "docs/drawing-editor.md"
|
|
2341
|
+
}
|
|
2342
|
+
},
|
|
2292
2343
|
{
|
|
2293
2344
|
"id": "color-picker",
|
|
2294
2345
|
"storyId": "input/color-picker",
|
package/docs/timeline.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Timeline contract
|
|
2
2
|
|
|
3
|
+
## 기본 여행 일지 (2026-10-27, 개발 소스·미게시)
|
|
4
|
+
|
|
5
|
+
사용자 승인 시안 「여행 일지」를 기본형으로 지정했다. 기본 `variant="journal"`은 배경 박스 없이
|
|
6
|
+
8px dot·1px connector와 위아래 16px 여백을 사용한다. 수동 기록은 전체 설명과 독립 행동을 유지하고,
|
|
7
|
+
선택형은 선택한 기록의 설명만 펼친다. 같은 기록을 다시 누르면 지도 선택을 유지하면서 상세를 접는다.
|
|
8
|
+
새 선택(외부 지도·날짜 포함)은 해당 기록을 펼친다. 제목·시각은 남는다.
|
|
9
|
+
|
|
10
|
+
Web은 disclosure button 목록과 `aria-expanded`·`aria-controls`, Native는 selected·expanded 상태를 제공한다.
|
|
11
|
+
선택 색을 진행 상태로 해석하지 않으며 사건 tone과 행동/가상화 경계는 보존한다.
|
|
12
|
+
이전 listbox·면/테두리 표현은 `variant="record"`로 명시할 때 제공한다.
|
|
13
|
+
이하 2026-10-23까지의 선택 면/listbox 설명은 이 호환 표현의 이력이다.
|
|
14
|
+
상세 소비·영향 범위는 [사용 지침](usage/components/timeline.md)을 따른다.
|
|
15
|
+
|
|
3
16
|
## 문제
|
|
4
17
|
|
|
5
18
|
이미 일어난 일들을 시간 순서로 보여준다 — 야잘알의 경기 플레이 기록(PBP, "1회 초 안타 →
|
package/docs/usage/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[선택 기준](SELECTION.md)으로 그대로 사용·공개 슬롯 확장·공통 API 보완·제품 고유 기능 연결을 고른다. 설치 버전의 지침을 본다: `node_modules/@hjmds/design-contracts/docs/usage/`.
|
|
8
8
|
이름을 모르면 [쉬운 말로 찾고 비교하기](FINDING.md)에서 일상 표현과 선택 기준·요청 예시로 시작한다.
|
|
9
9
|
제공 기준은 확인한 기본 API 버전이며 최초 출시 버전이 아니다. 구성·화면은 각 API 지침의 제공 버전을 확인한다.
|
|
10
|
-
API 안정성은 1.
|
|
10
|
+
API 안정성은 1.48.0의 생성 manifest에서 읽은 정규(canonical) API 기준이다. 동반·선택형 확장은 개별 계약을 확인한다.
|
|
11
11
|
Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품 반영을 의미하지 않는다.
|
|
12
12
|
`분류`는 Storybook 제목 `<배포|실험>/<단계>/<분류>/<항목>`의 셋째 마디이고, 토큰·구성·화면은 Storybook 메뉴와 같은 순서다.
|
|
13
13
|
|
|
@@ -95,6 +95,7 @@ Storybook 배포/실험은 예제 분류이며 npm 게시·기기 검증·제품
|
|
|
95
95
|
| [DesignSystemProvider](components/design-system-provider.md) | 기반 기능 | 앱 루트에 한 번 둔다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
96
96
|
| [Dialog](components/dialog.md) | 오버레이 | 화면 흐름을 잠시 멈추고 사용자의 주의가 필요한 **짧은 작업**에 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
97
97
|
| [Divider](components/divider.md) | 레이아웃 | 서로 다른 내용 묶음 사이에 얇은 구분선이 필요할 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
98
|
+
| [DrawingEditor](components/drawing-editor.md) | 입력 | 펜·지우개로 그림을 그리고 이미지로 저장하는 전체 편집 화면에 쓴다. | 미게시(1.48.0 이후) | Web · Native | Web beta / Native beta | 실험 |
|
|
98
99
|
| [EditorScreen](components/editor-screen.md) | 레이아웃 | 글쓰기·프로필 수정처럼 한 화면 전체가 편집 흐름일 때 쓴다. | 1.17.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
99
100
|
| [EffectSurface](components/effect-surface.md) | 시각 효과 | 환영·온보딩·빈 히어로처럼 분위기를 주는 배경이 필요할 때 내용 뒤에 장식 레이어(mesh·glow·grain)를 깐다. | 1.12.1 | Web · Native | 개별 API 계약 참조 | 배포 |
|
|
100
101
|
| [EmptyState](components/empty-state.md) | 상태와 알림 | 목록이 비었거나 검색 결과가 0건이라 **아직 없음**을 알릴 때 쓴다. | 1.12.1 | Web · Native | Web stable / Native stable | 배포 |
|
|
@@ -82,6 +82,7 @@ Web·Native 모두 기존 `raised` Surface의 테두리·그림자를 재사용
|
|
|
82
82
|
| prop | 값 | 기본값 | 설명 |
|
|
83
83
|
| --- | --- | --- | --- |
|
|
84
84
|
| `tone` | `default` · `raised` · `accent` · `sunken` · `subtle` · `selected`(Surface tone) | `raised` | 테두리와 공통 raised shadow로 입체감 표시. 평면 카드는 `tone="default"` 지정 |
|
|
85
|
+
| `badgesPlacement` | `body` · `corner` | `body` | 개발 소스·미게시. `corner`는 짧은 비상호작용 배지를 카드 우상단 8px에 12도 기울여 겹친다. 본문 높이를 늘리지 않는다. 다에리 NEW 배지 유무로 카드 높이가 달라진 문제를 해결하며 기존 `mediaBadges`의 배경 그림 전용 분류와 구분한다 |
|
|
85
86
|
| `badgesAlign` | `start` · `center` | `start` | 미게시. 들판 대표 카드처럼 그림 아래의 배지 묶음을 가운데 배치할 때 `center` 사용. 줄바꿈된 행에도 적용 |
|
|
86
87
|
| `bordered` | `boolean` | `true` | Surface 기본 `false`와 다르다 |
|
|
87
88
|
| `padding` | spacing 이름 | `md`(16) | — |
|