@hjmds/design-contracts 1.13.1 → 1.14.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.
Files changed (117) hide show
  1. package/dist/agreement.d.ts +7 -1
  2. package/dist/agreement.d.ts.map +1 -1
  3. package/dist/agreement.js +14 -3
  4. package/dist/agreement.js.map +1 -1
  5. package/dist/behaviors.d.ts +1 -1
  6. package/dist/catalog.d.ts +4 -0
  7. package/dist/catalog.d.ts.map +1 -1
  8. package/dist/content-transition.d.ts +17 -0
  9. package/dist/content-transition.d.ts.map +1 -1
  10. package/dist/content-transition.js +21 -0
  11. package/dist/content-transition.js.map +1 -1
  12. package/dist/date-entry.d.ts +71 -0
  13. package/dist/date-entry.d.ts.map +1 -0
  14. package/dist/date-entry.js +78 -0
  15. package/dist/date-entry.js.map +1 -0
  16. package/dist/document-resource.d.ts +104 -0
  17. package/dist/document-resource.d.ts.map +1 -0
  18. package/dist/document-resource.js +77 -0
  19. package/dist/document-resource.js.map +1 -0
  20. package/dist/effect-surface.d.ts +6 -1
  21. package/dist/effect-surface.d.ts.map +1 -1
  22. package/dist/effect-surface.js +5 -2
  23. package/dist/effect-surface.js.map +1 -1
  24. package/dist/field-group.d.ts +47 -0
  25. package/dist/field-group.d.ts.map +1 -0
  26. package/dist/field-group.js +92 -0
  27. package/dist/field-group.js.map +1 -0
  28. package/dist/image.d.ts +17 -0
  29. package/dist/image.d.ts.map +1 -1
  30. package/dist/image.js +19 -0
  31. package/dist/image.js.map +1 -1
  32. package/dist/internal/effect-noise.d.ts +2 -0
  33. package/dist/internal/effect-noise.d.ts.map +1 -0
  34. package/dist/internal/effect-noise.js +4 -0
  35. package/dist/internal/effect-noise.js.map +1 -0
  36. package/dist/progressive-blur.d.ts +32 -0
  37. package/dist/progressive-blur.d.ts.map +1 -0
  38. package/dist/progressive-blur.js +28 -0
  39. package/dist/progressive-blur.js.map +1 -0
  40. package/dist/reference-controls.d.ts +32 -0
  41. package/dist/reference-controls.d.ts.map +1 -0
  42. package/dist/reference-controls.js +28 -0
  43. package/dist/reference-controls.js.map +1 -0
  44. package/dist/scroll-progress.d.ts +7 -1
  45. package/dist/scroll-progress.d.ts.map +1 -1
  46. package/dist/scroll-progress.js +21 -2
  47. package/dist/scroll-progress.js.map +1 -1
  48. package/dist/text-annotation.d.ts +43 -0
  49. package/dist/text-annotation.d.ts.map +1 -0
  50. package/dist/text-annotation.js +137 -0
  51. package/dist/text-annotation.js.map +1 -0
  52. package/dist/version.d.ts +1 -1
  53. package/dist/version.js +1 -1
  54. package/dist/version.js.map +1 -1
  55. package/docs/agreement.md +14 -0
  56. package/docs/dialog.md +16 -1
  57. package/docs/effect-surface.md +19 -3
  58. package/docs/generated/component-maturity.md +1 -1
  59. package/docs/generated/renderer-evidence.json +3 -3
  60. package/docs/generated/renderer-evidence.md +1 -1
  61. package/docs/generated/showcase-manifest.json +1 -1
  62. package/docs/image.md +17 -0
  63. package/docs/optional-adapters.md +25 -0
  64. package/docs/popover.md +15 -0
  65. package/docs/rating.md +6 -1
  66. package/docs/reference-controls.md +40 -0
  67. package/docs/task-list.md +15 -1
  68. package/docs/text-annotation.md +85 -0
  69. package/docs/usage/README.md +18 -1
  70. package/docs/usage/components/agreement.md +13 -3
  71. package/docs/usage/components/alert-dialog.md +7 -1
  72. package/docs/usage/components/avatar.md +33 -1
  73. package/docs/usage/components/card.md +7 -1
  74. package/docs/usage/components/carousel.md +5 -1
  75. package/docs/usage/components/chat-message.md +11 -1
  76. package/docs/usage/components/chip.md +5 -0
  77. package/docs/usage/components/content-transition.md +28 -4
  78. package/docs/usage/components/dialog.md +18 -1
  79. package/docs/usage/components/effect-surface.md +4 -2
  80. package/docs/usage/components/empty-state.md +10 -2
  81. package/docs/usage/components/field.md +23 -0
  82. package/docs/usage/components/form.md +6 -1
  83. package/docs/usage/components/image-comparison.md +82 -0
  84. package/docs/usage/components/image.md +81 -2
  85. package/docs/usage/components/keyboard-avoiding.md +6 -1
  86. package/docs/usage/components/link.md +3 -1
  87. package/docs/usage/components/list-row.md +3 -1
  88. package/docs/usage/components/list.md +6 -1
  89. package/docs/usage/components/message-composer.md +5 -0
  90. package/docs/usage/components/popover.md +7 -1
  91. package/docs/usage/components/progress.md +28 -0
  92. package/docs/usage/components/progressive-blur.md +113 -0
  93. package/docs/usage/components/rating.md +74 -0
  94. package/docs/usage/components/search-field.md +10 -0
  95. package/docs/usage/components/search-screen.md +5 -0
  96. package/docs/usage/components/segmented-control.md +17 -0
  97. package/docs/usage/components/statistic.md +11 -0
  98. package/docs/usage/components/tags-input.md +5 -0
  99. package/docs/usage/components/toast.md +5 -0
  100. package/docs/usage/components/upload-item.md +3 -1
  101. package/docs/usage/compositions/action-feedback.md +77 -0
  102. package/docs/usage/compositions/adaptive-content.md +81 -0
  103. package/docs/usage/compositions/context-toolbar.md +85 -0
  104. package/docs/usage/compositions/date-entry.md +108 -0
  105. package/docs/usage/compositions/document-resource.md +124 -0
  106. package/docs/usage/compositions/field-group.md +104 -0
  107. package/docs/usage/compositions/illustrated-outcome.md +91 -0
  108. package/docs/usage/compositions/live-list.md +104 -0
  109. package/docs/usage/compositions/optional-adapters.md +1 -1
  110. package/docs/usage/compositions/origin-dialog.md +108 -0
  111. package/docs/usage/compositions/selection-motion.md +73 -0
  112. package/docs/usage/compositions/texture-comparison.md +86 -0
  113. package/docs/usage/compositions/upload-recovery.md +80 -0
  114. package/docs/usage/compositions/video-dialog.md +100 -0
  115. package/docs/usage/screens/flow-onboarding.md +5 -3
  116. package/docs/usage/screens/product-bento.md +117 -0
  117. package/package.json +37 -1
@@ -29,6 +29,8 @@ export type AgreementDescriptor<Id extends string = string> = Readonly<{
29
29
  /** 전체 동의 행의 라벨. 필수이므로 renderer가 임의 문구를 만들지 않는다. */
30
30
  allLabel: string;
31
31
  items: readonly AgreementItemDescriptor<Id>[];
32
+ /** Freeze consent changes during submission; detail reading remains available. */
33
+ disabled?: boolean;
32
34
  }>;
33
35
  export declare function validateAgreementDescriptor<Id extends string>(descriptor: AgreementDescriptor<Id>): void;
34
36
  export type AgreementState<Id extends string = string> = Readonly<{
@@ -130,6 +132,9 @@ export declare const agreementRecipe: {
130
132
  alpha?: number;
131
133
  }>;
132
134
  };
135
+ readonly itemLayout: {
136
+ readonly labelBasis: "70%";
137
+ };
133
138
  readonly detail: {
134
139
  readonly color: Readonly<{
135
140
  source: "theme";
@@ -158,11 +163,12 @@ export declare const agreementRecipe: {
158
163
  readonly width: 2;
159
164
  readonly offset: 2;
160
165
  };
166
+ readonly disabledOpacity: 0.5;
161
167
  };
162
168
  };
163
169
  export declare const agreementBehavior: {
164
170
  readonly controlled: readonly ["checkedIds", "defaultCheckedIds", "onCheckedIdsChange"];
165
- readonly inputs: readonly ["items", "allLabel", "accessibilityLabel"];
171
+ readonly inputs: readonly ["items", "allLabel", "accessibilityLabel", "disabled"];
166
172
  readonly events: readonly ["onDetail"];
167
173
  readonly stateAxes: {
168
174
  readonly availability: readonly ["enabled", "disabled"];
@@ -1 +1 @@
1
- {"version":3,"file":"agreement.d.ts","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,uBAAuB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAC5D,qBAAqB,CAAC,EAAE,CAAC,GACvB,QAAQ,CAAC;IACP,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD,CAAC,CAAC;AAEP,MAAM,MAAM,mBAAmB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACrE,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,uBAAuB,CAAC,EAAE,CAAC,EAAE,CAAC;CAC/C,CAAC,CAAC;AAQH,wBAAgB,2BAA2B,CAAC,EAAE,SAAS,MAAM,EAC3D,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,GAClC,IAAI,CAyBN;AAED,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChE,8CAA8C;IAC9C,GAAG,EAAE,aAAa,CAAC;IACnB,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,kBAAkB,EAAE,SAAS,EAAE,EAAE,CAAC;CACnC,CAAC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,MAAM,EACrD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,cAAc,CAAC,EAAE,CAAC,CAapB;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EACnD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,EAC3B,EAAE,EAAE,EAAE,GACL,WAAW,CAAC,EAAE,CAAC,CAGjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAClD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,WAAW,CAAC,EAAE,CAAC,CASjB;AAED,gCAAgC;AAChC,wBAAgB,2BAA2B,CAAC,EAAE,SAAS,MAAM,EAC3D,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,WAAW,CAAC,EAAE,CAAC,CAGjB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;CA4BO,CAAC"}
1
+ {"version":3,"file":"agreement.d.ts","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"AAKA,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,uBAAuB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAC5D,qBAAqB,CAAC,EAAE,CAAC,GACvB,QAAQ,CAAC;IACP,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,QAAQ,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD,CAAC,CAAC;AAEP,MAAM,MAAM,mBAAmB,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IACrE,0CAA0C;IAC1C,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,uBAAuB,CAAC,EAAE,CAAC,EAAE,CAAC;IAC9C,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AAQH,wBAAgB,2BAA2B,CAAC,EAAE,SAAS,MAAM,EAC3D,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,GAClC,IAAI,CA0BN;AAED,MAAM,MAAM,cAAc,CAAC,EAAE,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,CAAC;IAChE,8CAA8C;IAC9C,GAAG,EAAE,aAAa,CAAC;IACnB,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,kBAAkB,EAAE,SAAS,EAAE,EAAE,CAAC;CACnC,CAAC,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,MAAM,EACrD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,cAAc,CAAC,EAAE,CAAC,CAapB;AAED,gDAAgD;AAChD,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EACnD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,EAC3B,EAAE,EAAE,EAAE,GACL,WAAW,CAAC,EAAE,CAAC,CAMjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAClD,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,WAAW,CAAC,EAAE,CAAC,CAUjB;AAED,gCAAgC;AAChC,wBAAgB,2BAA2B,CAAC,EAAE,SAAS,MAAM,EAC3D,UAAU,EAAE,mBAAmB,CAAC,EAAE,CAAC,EACnC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,GAC1B,WAAW,CAAC,EAAE,CAAC,CAGjB;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0C3B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;CA4BO,CAAC"}
package/dist/agreement.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { collectionItemContract, focusIndicatorContract } from "./component-contracts.js";
2
- import { control, spacing } from "./foundations.js";
2
+ import { control, opacity, spacing } from "./foundations.js";
3
3
  import { semanticColors } from "./semantic-colors.js";
4
4
  import { reconcileCheckboxSelection, toggleCheckboxSelection, } from "./selection-helpers.js";
5
5
  function assertNonEmpty(value, field) {
@@ -13,6 +13,8 @@ export function validateAgreementDescriptor(descriptor) {
13
13
  if (!Array.isArray(descriptor.items) || descriptor.items.length === 0) {
14
14
  throw new RangeError("Agreement must contain at least one item");
15
15
  }
16
+ if (descriptor.disabled !== undefined && typeof descriptor.disabled !== "boolean")
17
+ throw new TypeError("Agreement disabled must be a boolean");
16
18
  const ids = new Set();
17
19
  for (const item of descriptor.items) {
18
20
  assertNonEmpty(item.id, "item id");
@@ -54,6 +56,10 @@ export function resolveAgreementState(descriptor, checkedIds) {
54
56
  /** 개별 항목 토글. 비활성 항목 보호는 공용 helper가 이미 갖고 있다. */
55
57
  export function toggleAgreementItem(descriptor, checkedIds, id) {
56
58
  validateAgreementDescriptor(descriptor);
59
+ // Utilverse registration must freeze required consents during a request.
60
+ // Disabling each required item is invalid and would change the denominator.
61
+ if (descriptor.disabled)
62
+ return checkedIds;
57
63
  return toggleCheckboxSelection(descriptor.items, checkedIds, id);
58
64
  }
59
65
  /**
@@ -63,6 +69,8 @@ export function toggleAgreementItem(descriptor, checkedIds, id) {
63
69
  */
64
70
  export function toggleAgreementAll(descriptor, checkedIds) {
65
71
  const { all } = resolveAgreementState(descriptor, checkedIds);
72
+ if (descriptor.disabled)
73
+ return checkedIds;
66
74
  const next = new Set(checkedIds);
67
75
  for (const item of descriptor.items) {
68
76
  if (item.disabled)
@@ -96,6 +104,9 @@ export const agreementRecipe = {
96
104
  color: semanticColors.content.primary,
97
105
  },
98
106
  item: collectionItemContract,
107
+ // Reserve most row width for consent text. Long detail labels wrap below it
108
+ // instead of squeezing large Korean labels into one-character columns.
109
+ itemLayout: { labelBasis: "70%" },
99
110
  detail: {
100
111
  color: semanticColors.content.secondary,
101
112
  textVariant: "label",
@@ -103,11 +114,11 @@ export const agreementRecipe = {
103
114
  },
104
115
  required: { color: semanticColors.content.brand, textVariant: "label" },
105
116
  gap: spacing.xs,
106
- states: { focus: focusIndicatorContract },
117
+ states: { focus: focusIndicatorContract, disabledOpacity: opacity.disabled },
107
118
  };
108
119
  export const agreementBehavior = {
109
120
  controlled: ["checkedIds", "defaultCheckedIds", "onCheckedIdsChange"],
110
- inputs: ["items", "allLabel", "accessibilityLabel"],
121
+ inputs: ["items", "allLabel", "accessibilityLabel", "disabled"],
111
122
  events: ["onDetail"],
112
123
  stateAxes: {
113
124
  availability: ["enabled", "disabled"],
@@ -1 +1 @@
1
- {"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport {\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n type CheckboxSelectionItem,\n type CheckboxState,\n} from \"./selection-helpers.js\";\n\n/**\n * 가입·결제 앞에 서는 \"약관 동의\" 묶음이다. CheckboxGroup으로 매번 조립하던 것을\n * 계약으로 올리는 이유는 세 가지가 **체크박스 목록이 아니라 법적 절차**이기 때문이다.\n *\n * 1. 필수/선택이 제출 가능 여부를 결정한다 — CheckboxGroup은 그 판정을 갖지 않는다.\n * 2. 전체 동의는 자식의 합이지 별도 항목이 아니다(DataTable 머리글·TreeSelect 부모와\n * 같은 파생 관계). 저장되는 것은 개별 항목뿐이다.\n * 3. 각 항목은 \"읽을 수 있어야\" 한다 — 상세 보기 경로가 없는 동의는 동의가 아니다.\n * 그래서 `detail`은 renderer가 장식으로 넣는 화살표가 아니라 계약된 행동이다.\n *\n * 문구·링크 주소·법적 유효성은 제품이 소유한다. 이 계약은 판정과 배치만 갖는다.\n */\nexport type AgreementItemDescriptor<Id extends string = string> =\n CheckboxSelectionItem<Id> &\n Readonly<{\n /** 필수 항목은 하나라도 비면 제출을 막는다. 기본값은 선택(false). */\n required?: boolean;\n /**\n * 전문을 여는 경로. 제품이 링크(`href`)로 열지 시트로 열지는 renderer 밖의\n * 결정이라 여기서는 \"열 수 있다\"는 사실만 계약한다.\n */\n detail?: Readonly<{ label: string; href?: string }>;\n }>;\n\nexport type AgreementDescriptor<Id extends string = string> = Readonly<{\n /** 묶음 전체의 접근성 이름. \"약관 동의\"처럼 제품이 현지화한다. */\n accessibilityLabel: string;\n /** 전체 동의 행의 라벨. 필수이므로 renderer가 임의 문구를 만들지 않는다. */\n allLabel: string;\n items: readonly AgreementItemDescriptor<Id>[];\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Agreement ${field} must not be empty`);\n }\n}\n\nexport function validateAgreementDescriptor<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n): void {\n assertNonEmpty(descriptor.accessibilityLabel, \"accessibilityLabel\");\n assertNonEmpty(descriptor.allLabel, \"allLabel\");\n if (!Array.isArray(descriptor.items) || descriptor.items.length === 0) {\n throw new RangeError(\"Agreement must contain at least one item\");\n }\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n assertNonEmpty(item.id, \"item id\");\n assertNonEmpty(item.label, \"item label\");\n if (ids.has(item.id)) throw new TypeError(`Duplicate Agreement item id: ${item.id}`);\n ids.add(item.id);\n if (item.detail !== undefined) {\n assertNonEmpty(item.detail.label, `item ${item.id} detail label`);\n }\n if (item.required === true && item.disabled === true) {\n /*\n 비활성 필수 항목은 사용자가 영원히 제출할 수 없는 화면을 만든다. 조용히\n 허용하면 \"버튼이 왜 안 눌리는지\" 알 수 없는 상태가 되므로 여기서 막는다.\n */\n throw new TypeError(\n `Agreement item ${item.id} cannot be both required and disabled`,\n );\n }\n }\n}\n\nexport type AgreementState<Id extends string = string> = Readonly<{\n /** 전체 동의 행이 그릴 tri-state. 개별 항목의 합에서만 나온다. */\n all: CheckboxState;\n /** 필수 항목이 모두 체크됐는가 — 제품의 제출 버튼이 읽는 값. */\n satisfied: boolean;\n /** 아직 체크되지 않은 필수 항목. 제품이 \"무엇이 남았는지\" 문장을 만든다. */\n missingRequiredIds: readonly Id[];\n}>;\n\n/**\n * 비활성 항목은 분모에서 뺀다 — 사용자가 바꿀 수 없는 것을 \"덜 동의했다\"고 셀 수\n * 없기 때문이다(`resolveDataTableSelectAllState`·`resolveTreeCheckedStates`와 같은 규칙).\n * 필수 항목은 비활성일 수 없으므로(위 validate) `satisfied` 판정에는 이 예외가 없다.\n */\nexport function resolveAgreementState<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): AgreementState<Id> {\n validateAgreementDescriptor(descriptor);\n const selectable = descriptor.items.filter((item) => !item.disabled);\n const checkedCount = selectable.filter((item) => checkedIds.has(item.id)).length;\n const all: CheckboxState = selectable.length === 0 || checkedCount === 0\n ? false\n : checkedCount === selectable.length\n ? true\n : \"mixed\";\n const missingRequiredIds = descriptor.items\n .filter((item) => item.required === true && !checkedIds.has(item.id))\n .map((item) => item.id);\n return { all, satisfied: missingRequiredIds.length === 0, missingRequiredIds };\n}\n\n/** 개별 항목 토글. 비활성 항목 보호는 공용 helper가 이미 갖고 있다. */\nexport function toggleAgreementItem<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n id: Id,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return toggleCheckboxSelection(descriptor.items, checkedIds, id);\n}\n\n/**\n * 전체 동의는 \"모두 체크됨\"의 반대로 간다 — mixed에서 누르면 채운다(공용\n * `getCheckboxNextState`의 기본값과 같은 관습). 비활성 항목의 현재 상태는 건드리지\n * 않는다: 그 값은 사용자가 만든 것이 아니라 제품이 고정한 것이다.\n */\nexport function toggleAgreementAll<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n const { all } = resolveAgreementState(descriptor, checkedIds);\n const next = new Set(checkedIds);\n for (const item of descriptor.items) {\n if (item.disabled) continue;\n if (all === true) next.delete(item.id);\n else next.add(item.id);\n }\n return next;\n}\n\n/** 목록에서 사라진 항목의 동의는 남기지 않는다. */\nexport function reconcileAgreementSelection<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return reconcileCheckboxSelection(descriptor.items, checkedIds);\n}\n\n/**\n * 전체 동의 행은 개별 행보다 시각적으로 무겁다 — 목록의 제목 역할을 하기 때문이다.\n * 나머지는 `collectionItemContract`를 그대로 쓴다(Menu·Tree·ListRow와 같은 행 chrome).\n */\nexport const agreementRecipe = {\n slots: [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"] as const,\n all: {\n minHeight: control.minTouchTarget,\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n background: semanticColors.canvas,\n radius: \"md\" as const,\n textVariant: \"bodyLarge\" as const,\n color: semanticColors.content.primary,\n },\n item: collectionItemContract,\n detail: {\n color: semanticColors.content.secondary,\n textVariant: \"label\" as const,\n minHeight: control.minTouchTarget,\n },\n required: { color: semanticColors.content.brand, textVariant: \"label\" as const },\n gap: spacing.xs,\n states: { focus: focusIndicatorContract },\n} as const satisfies {\n slots: readonly [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"];\n all: {\n minHeight: number;\n gap: number;\n paddingHorizontal: number;\n paddingVertical: number;\n background: ColorReference;\n radius: \"md\";\n textVariant: \"bodyLarge\";\n color: ColorReference;\n };\n item: typeof collectionItemContract;\n detail: { color: ColorReference; textVariant: \"label\"; minHeight: number };\n required: { color: ColorReference; textVariant: \"label\" };\n gap: number;\n states: { focus: typeof focusIndicatorContract };\n};\n\nexport const agreementBehavior = {\n controlled: [\"checkedIds\", \"defaultCheckedIds\", \"onCheckedIdsChange\"],\n inputs: [\"items\", \"allLabel\", \"accessibilityLabel\"],\n events: [\"onDetail\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"unchecked\", \"checked\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"checkbox\", \"link\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\"],\n focus: \"native\",\n },\n native: {\n roles: [\"checkbox\", \"link\", \"button\"],\n states: [\"checked\", \"disabled\"],\n actions: [\"toggle\", \"toggleAll\", \"openDetail\"],\n },\n scenarios: [\n \"all-agree-is-derived-from-the-items-never-stored-as-its-own-value\",\n \"checking-all-checks-every-enabled-item-and-leaves-disabled-ones-untouched\",\n \"required-items-alone-decide-whether-the-product-may-submit\",\n \"a-required-item-can-never-be-disabled-the-descriptor-is-rejected\",\n \"every-item-may-open-its-full-text-and-that-control-is-a-separate-tab-stop\",\n \"the-detail-control-never-toggles-the-agreement-it-only-opens-the-text\",\n \"optional-items-never-block-submission-and-are-announced-as-optional\",\n \"removing-an-item-drops-its-consent-instead-of-keeping-an-orphan-id\",\n ],\n} as const satisfies BehaviorContract;\n"]}
1
+ {"version":3,"file":"agreement.js","sourceRoot":"","sources":["../src/agreement.ts"],"names":[],"mappings":"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","sourcesContent":["import type { BehaviorContract } from \"./behaviors.js\";\nimport type { ColorReference } from \"./color-references.js\";\nimport { collectionItemContract, focusIndicatorContract } from \"./component-contracts.js\";\nimport { control, opacity, spacing } from \"./foundations.js\";\nimport { semanticColors } from \"./semantic-colors.js\";\nimport {\n reconcileCheckboxSelection,\n toggleCheckboxSelection,\n type CheckboxSelectionItem,\n type CheckboxState,\n} from \"./selection-helpers.js\";\n\n/**\n * 가입·결제 앞에 서는 \"약관 동의\" 묶음이다. CheckboxGroup으로 매번 조립하던 것을\n * 계약으로 올리는 이유는 세 가지가 **체크박스 목록이 아니라 법적 절차**이기 때문이다.\n *\n * 1. 필수/선택이 제출 가능 여부를 결정한다 — CheckboxGroup은 그 판정을 갖지 않는다.\n * 2. 전체 동의는 자식의 합이지 별도 항목이 아니다(DataTable 머리글·TreeSelect 부모와\n * 같은 파생 관계). 저장되는 것은 개별 항목뿐이다.\n * 3. 각 항목은 \"읽을 수 있어야\" 한다 — 상세 보기 경로가 없는 동의는 동의가 아니다.\n * 그래서 `detail`은 renderer가 장식으로 넣는 화살표가 아니라 계약된 행동이다.\n *\n * 문구·링크 주소·법적 유효성은 제품이 소유한다. 이 계약은 판정과 배치만 갖는다.\n */\nexport type AgreementItemDescriptor<Id extends string = string> =\n CheckboxSelectionItem<Id> &\n Readonly<{\n /** 필수 항목은 하나라도 비면 제출을 막는다. 기본값은 선택(false). */\n required?: boolean;\n /**\n * 전문을 여는 경로. 제품이 링크(`href`)로 열지 시트로 열지는 renderer 밖의\n * 결정이라 여기서는 \"열 수 있다\"는 사실만 계약한다.\n */\n detail?: Readonly<{ label: string; href?: string }>;\n }>;\n\nexport type AgreementDescriptor<Id extends string = string> = Readonly<{\n /** 묶음 전체의 접근성 이름. \"약관 동의\"처럼 제품이 현지화한다. */\n accessibilityLabel: string;\n /** 전체 동의 행의 라벨. 필수이므로 renderer가 임의 문구를 만들지 않는다. */\n allLabel: string;\n items: readonly AgreementItemDescriptor<Id>[];\n /** Freeze consent changes during submission; detail reading remains available. */\n disabled?: boolean;\n}>;\n\nfunction assertNonEmpty(value: string, field: string): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new TypeError(`Agreement ${field} must not be empty`);\n }\n}\n\nexport function validateAgreementDescriptor<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n): void {\n assertNonEmpty(descriptor.accessibilityLabel, \"accessibilityLabel\");\n assertNonEmpty(descriptor.allLabel, \"allLabel\");\n if (!Array.isArray(descriptor.items) || descriptor.items.length === 0) {\n throw new RangeError(\"Agreement must contain at least one item\");\n }\n if (descriptor.disabled !== undefined && typeof descriptor.disabled !== \"boolean\") throw new TypeError(\"Agreement disabled must be a boolean\");\n const ids = new Set<Id>();\n for (const item of descriptor.items) {\n assertNonEmpty(item.id, \"item id\");\n assertNonEmpty(item.label, \"item label\");\n if (ids.has(item.id)) throw new TypeError(`Duplicate Agreement item id: ${item.id}`);\n ids.add(item.id);\n if (item.detail !== undefined) {\n assertNonEmpty(item.detail.label, `item ${item.id} detail label`);\n }\n if (item.required === true && item.disabled === true) {\n /*\n 비활성 필수 항목은 사용자가 영원히 제출할 수 없는 화면을 만든다. 조용히\n 허용하면 \"버튼이 왜 안 눌리는지\" 알 수 없는 상태가 되므로 여기서 막는다.\n */\n throw new TypeError(\n `Agreement item ${item.id} cannot be both required and disabled`,\n );\n }\n }\n}\n\nexport type AgreementState<Id extends string = string> = Readonly<{\n /** 전체 동의 행이 그릴 tri-state. 개별 항목의 합에서만 나온다. */\n all: CheckboxState;\n /** 필수 항목이 모두 체크됐는가 — 제품의 제출 버튼이 읽는 값. */\n satisfied: boolean;\n /** 아직 체크되지 않은 필수 항목. 제품이 \"무엇이 남았는지\" 문장을 만든다. */\n missingRequiredIds: readonly Id[];\n}>;\n\n/**\n * 비활성 항목은 분모에서 뺀다 — 사용자가 바꿀 수 없는 것을 \"덜 동의했다\"고 셀 수\n * 없기 때문이다(`resolveDataTableSelectAllState`·`resolveTreeCheckedStates`와 같은 규칙).\n * 필수 항목은 비활성일 수 없으므로(위 validate) `satisfied` 판정에는 이 예외가 없다.\n */\nexport function resolveAgreementState<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): AgreementState<Id> {\n validateAgreementDescriptor(descriptor);\n const selectable = descriptor.items.filter((item) => !item.disabled);\n const checkedCount = selectable.filter((item) => checkedIds.has(item.id)).length;\n const all: CheckboxState = selectable.length === 0 || checkedCount === 0\n ? false\n : checkedCount === selectable.length\n ? true\n : \"mixed\";\n const missingRequiredIds = descriptor.items\n .filter((item) => item.required === true && !checkedIds.has(item.id))\n .map((item) => item.id);\n return { all, satisfied: missingRequiredIds.length === 0, missingRequiredIds };\n}\n\n/** 개별 항목 토글. 비활성 항목 보호는 공용 helper가 이미 갖고 있다. */\nexport function toggleAgreementItem<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n id: Id,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n // Utilverse registration must freeze required consents during a request.\n // Disabling each required item is invalid and would change the denominator.\n if (descriptor.disabled) return checkedIds;\n return toggleCheckboxSelection(descriptor.items, checkedIds, id);\n}\n\n/**\n * 전체 동의는 \"모두 체크됨\"의 반대로 간다 — mixed에서 누르면 채운다(공용\n * `getCheckboxNextState`의 기본값과 같은 관습). 비활성 항목의 현재 상태는 건드리지\n * 않는다: 그 값은 사용자가 만든 것이 아니라 제품이 고정한 것이다.\n */\nexport function toggleAgreementAll<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n const { all } = resolveAgreementState(descriptor, checkedIds);\n if (descriptor.disabled) return checkedIds;\n const next = new Set(checkedIds);\n for (const item of descriptor.items) {\n if (item.disabled) continue;\n if (all === true) next.delete(item.id);\n else next.add(item.id);\n }\n return next;\n}\n\n/** 목록에서 사라진 항목의 동의는 남기지 않는다. */\nexport function reconcileAgreementSelection<Id extends string>(\n descriptor: AgreementDescriptor<Id>,\n checkedIds: ReadonlySet<Id>,\n): ReadonlySet<Id> {\n validateAgreementDescriptor(descriptor);\n return reconcileCheckboxSelection(descriptor.items, checkedIds);\n}\n\n/**\n * 전체 동의 행은 개별 행보다 시각적으로 무겁다 — 목록의 제목 역할을 하기 때문이다.\n * 나머지는 `collectionItemContract`를 그대로 쓴다(Menu·Tree·ListRow와 같은 행 chrome).\n */\nexport const agreementRecipe = {\n slots: [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"] as const,\n all: {\n minHeight: control.minTouchTarget,\n gap: spacing.sm,\n paddingHorizontal: spacing.md,\n paddingVertical: spacing.sm,\n background: semanticColors.canvas,\n radius: \"md\" as const,\n textVariant: \"bodyLarge\" as const,\n color: semanticColors.content.primary,\n },\n item: collectionItemContract,\n // Reserve most row width for consent text. Long detail labels wrap below it\n // instead of squeezing large Korean labels into one-character columns.\n itemLayout: { labelBasis: \"70%\" as const },\n detail: {\n color: semanticColors.content.secondary,\n textVariant: \"label\" as const,\n minHeight: control.minTouchTarget,\n },\n required: { color: semanticColors.content.brand, textVariant: \"label\" as const },\n gap: spacing.xs,\n states: { focus: focusIndicatorContract, disabledOpacity: opacity.disabled },\n} as const satisfies {\n slots: readonly [\"root\", \"all\", \"list\", \"item\", \"label\", \"detail\"];\n all: {\n minHeight: number;\n gap: number;\n paddingHorizontal: number;\n paddingVertical: number;\n background: ColorReference;\n radius: \"md\";\n textVariant: \"bodyLarge\";\n color: ColorReference;\n };\n item: typeof collectionItemContract;\n itemLayout: { labelBasis: \"70%\" };\n detail: { color: ColorReference; textVariant: \"label\"; minHeight: number };\n required: { color: ColorReference; textVariant: \"label\" };\n gap: number;\n states: { focus: typeof focusIndicatorContract; disabledOpacity: number };\n};\n\nexport const agreementBehavior = {\n controlled: [\"checkedIds\", \"defaultCheckedIds\", \"onCheckedIdsChange\"],\n inputs: [\"items\", \"allLabel\", \"accessibilityLabel\", \"disabled\"],\n events: [\"onDetail\"],\n stateAxes: {\n availability: [\"enabled\", \"disabled\"],\n value: [\"unchecked\", \"checked\", \"mixed\"],\n },\n web: {\n roles: [\"group\", \"checkbox\", \"link\", \"button\"],\n keyboard: [\"Tab\", \"Space\", \"Enter\"],\n focus: \"native\",\n },\n native: {\n roles: [\"checkbox\", \"link\", \"button\"],\n states: [\"checked\", \"disabled\"],\n actions: [\"toggle\", \"toggleAll\", \"openDetail\"],\n },\n scenarios: [\n \"all-agree-is-derived-from-the-items-never-stored-as-its-own-value\",\n \"checking-all-checks-every-enabled-item-and-leaves-disabled-ones-untouched\",\n \"required-items-alone-decide-whether-the-product-may-submit\",\n \"a-required-item-can-never-be-disabled-the-descriptor-is-rejected\",\n \"every-item-may-open-its-full-text-and-that-control-is-a-separate-tab-stop\",\n \"the-detail-control-never-toggles-the-agreement-it-only-opens-the-text\",\n \"optional-items-never-block-submission-and-are-announced-as-optional\",\n \"removing-an-item-drops-its-consent-instead-of-keeping-an-orphan-id\",\n ],\n} as const satisfies BehaviorContract;\n"]}
@@ -702,7 +702,7 @@ export declare const behaviorRegistry: {
702
702
  };
703
703
  readonly agreement: {
704
704
  readonly controlled: readonly ["checkedIds", "defaultCheckedIds", "onCheckedIdsChange"];
705
- readonly inputs: readonly ["items", "allLabel", "accessibilityLabel"];
705
+ readonly inputs: readonly ["items", "allLabel", "accessibilityLabel", "disabled"];
706
706
  readonly events: readonly ["onDetail"];
707
707
  readonly stateAxes: {
708
708
  readonly availability: readonly ["enabled", "disabled"];
package/dist/catalog.d.ts CHANGED
@@ -2175,6 +2175,9 @@ export declare const recipeRegistry: {
2175
2175
  alpha?: number;
2176
2176
  }>;
2177
2177
  };
2178
+ readonly itemLayout: {
2179
+ readonly labelBasis: "70%";
2180
+ };
2178
2181
  readonly detail: {
2179
2182
  readonly color: Readonly<{
2180
2183
  source: "theme";
@@ -2203,6 +2206,7 @@ export declare const recipeRegistry: {
2203
2206
  readonly width: 2;
2204
2207
  readonly offset: 2;
2205
2208
  };
2209
+ readonly disabledOpacity: 0.5;
2206
2210
  };
2207
2211
  };
2208
2212
  readonly topRecipe: {
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGjB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,cAAc,CAAC"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiGjB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,cAAc,CAAC"}
@@ -14,4 +14,21 @@ export declare function resolveContentTransition(preset?: ContentTransitionPrese
14
14
  translateY: number;
15
15
  scale: number;
16
16
  };
17
+ /** Both rectangles must be measured in the same physical viewport coordinates.
18
+ * Router shared-element IDs are not a substitute for a local overlay's geometry. */
19
+ export type TransitionRect = Readonly<{
20
+ x: number;
21
+ y: number;
22
+ width: number;
23
+ height: number;
24
+ }>;
25
+ /** Invert the destination around its center so it starts at the trigger bounds.
26
+ * A renderer interpolates this transform to identity and owns cancellation,
27
+ * measurement freshness, presence and focus; this resolver never clones content. */
28
+ export declare function resolveOriginTransition(origin: TransitionRect | null | undefined, destination: TransitionRect | null | undefined, reducedMotion?: boolean): Readonly<{
29
+ translateX: number;
30
+ translateY: number;
31
+ scaleX: number;
32
+ scaleY: number;
33
+ }> | null;
17
34
  //# sourceMappingURL=content-transition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content-transition.d.ts","sourceRoot":"","sources":["../src/content-transition.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAC1E;oFACoF;AACpF,eAAO,MAAM,uBAAuB;;;;CAAgD,CAAC;AACrF;8EAC8E;AAC9E,wBAAgB,wBAAwB,CAAC,MAAM,GAAE,uBAAgC,EAAE,SAAS,GAAE,KAAK,GAAG,KAAa;;;;;EAQlH"}
1
+ {"version":3,"file":"content-transition.d.ts","sourceRoot":"","sources":["../src/content-transition.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAC1E;oFACoF;AACpF,eAAO,MAAM,uBAAuB;;;;CAAgD,CAAC;AACrF;8EAC8E;AAC9E,wBAAgB,wBAAwB,CAAC,MAAM,GAAE,uBAAgC,EAAE,SAAS,GAAE,KAAK,GAAG,KAAa;;;;;EAQlH;AAED;oFACoF;AACpF,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE/F;;oFAEoF;AACpF,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EACzC,WAAW,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC9C,aAAa,UAAQ,GACpB,QAAQ,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAe7F"}
@@ -12,4 +12,25 @@ export function resolveContentTransition(preset = "fade", direction = "ltr") {
12
12
  default: throw new TypeError("Unsupported content transition preset");
13
13
  }
14
14
  }
15
+ /** Invert the destination around its center so it starts at the trigger bounds.
16
+ * A renderer interpolates this transform to identity and owns cancellation,
17
+ * measurement freshness, presence and focus; this resolver never clones content. */
18
+ export function resolveOriginTransition(origin, destination, reducedMotion = false) {
19
+ // Missing/zero geometry occurs before layout and after trigger removal. Keep
20
+ // the canonical overlay available instead of throwing or guessing coordinates.
21
+ if (reducedMotion || !origin || !destination)
22
+ return null;
23
+ for (const rect of [origin, destination]) {
24
+ if (![rect.x, rect.y, rect.width, rect.height].every(Number.isFinite) || rect.width <= 0 || rect.height <= 0)
25
+ return null;
26
+ }
27
+ const transform = {
28
+ translateX: (origin.x - destination.x) + (origin.width - destination.width) / 2,
29
+ translateY: (origin.y - destination.y) + (origin.height - destination.height) / 2,
30
+ scaleX: origin.width / destination.width,
31
+ scaleY: origin.height / destination.height,
32
+ };
33
+ // Finite measurements can still overflow or underflow during subtraction/division.
34
+ return Object.values(transform).every(Number.isFinite) && transform.scaleX > 0 && transform.scaleY > 0 ? transform : null;
35
+ }
15
36
  //# sourceMappingURL=content-transition.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"content-transition.js","sourceRoot":"","sources":["../src/content-transition.ts"],"names":[],"mappings":"AACA;oFACoF;AACpF,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAW,CAAC;AACrF;8EAC8E;AAC9E,MAAM,UAAU,wBAAwB,CAAC,SAAkC,MAAM,EAAE,YAA2B,KAAK;IACjH,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3E,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACtG,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACzI,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,uBAAuB,CAAC,KAAK,EAAE,CAAC;QACxG,OAAO,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IACxE,CAAC;AACH,CAAC","sourcesContent":["export type ContentTransitionPreset = \"fade\" | \"rise\" | \"slide\" | \"scale\";\n/** Small local travel preserves context; these are presentation values, never\n * gesture activation thresholds. Retain the existing geometry for compatibility. */\nexport const contentTransitionMotion = { rise: 12, slide: 16, scale: 0.96 } as const;\n/** Bounded travel keeps decorative motion close to the destination.\n * Single-subtree recipes: preserve wrapping, focus and accessible content. */\nexport function resolveContentTransition(preset: ContentTransitionPreset = \"fade\", direction: \"ltr\" | \"rtl\" = \"ltr\") {\n switch (preset) {\n case \"fade\": return { opacity: 0, translateX: 0, translateY: 0, scale: 1 };\n case \"rise\": return { opacity: 0, translateX: 0, translateY: contentTransitionMotion.rise, scale: 1 };\n case \"slide\": return { opacity: 0, translateX: (direction === \"rtl\" ? -1 : 1) * contentTransitionMotion.slide, translateY: 0, scale: 1 };\n case \"scale\": return { opacity: 0, translateX: 0, translateY: 0, scale: contentTransitionMotion.scale };\n default: throw new TypeError(\"Unsupported content transition preset\");\n }\n}\n"]}
1
+ {"version":3,"file":"content-transition.js","sourceRoot":"","sources":["../src/content-transition.ts"],"names":[],"mappings":"AACA;oFACoF;AACpF,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAW,CAAC;AACrF;8EAC8E;AAC9E,MAAM,UAAU,wBAAwB,CAAC,SAAkC,MAAM,EAAE,YAA2B,KAAK;IACjH,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAC3E,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,uBAAuB,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACtG,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,uBAAuB,CAAC,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACzI,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,uBAAuB,CAAC,KAAK,EAAE,CAAC;QACxG,OAAO,CAAC,CAAC,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAMD;;oFAEoF;AACpF,MAAM,UAAU,uBAAuB,CACrC,MAAyC,EACzC,WAA8C,EAC9C,aAAa,GAAG,KAAK;IAErB,6EAA6E;IAC7E,+EAA+E;IAC/E,IAAI,aAAa,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC1D,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC5H,CAAC;IACD,MAAM,SAAS,GAAG;QAChB,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/E,UAAU,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC;QACjF,MAAM,EAAE,MAAM,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK;QACxC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,WAAW,CAAC,MAAM;KAC3C,CAAC;IACF,mFAAmF;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5H,CAAC","sourcesContent":["export type ContentTransitionPreset = \"fade\" | \"rise\" | \"slide\" | \"scale\";\n/** Small local travel preserves context; these are presentation values, never\n * gesture activation thresholds. Retain the existing geometry for compatibility. */\nexport const contentTransitionMotion = { rise: 12, slide: 16, scale: 0.96 } as const;\n/** Bounded travel keeps decorative motion close to the destination.\n * Single-subtree recipes: preserve wrapping, focus and accessible content. */\nexport function resolveContentTransition(preset: ContentTransitionPreset = \"fade\", direction: \"ltr\" | \"rtl\" = \"ltr\") {\n switch (preset) {\n case \"fade\": return { opacity: 0, translateX: 0, translateY: 0, scale: 1 };\n case \"rise\": return { opacity: 0, translateX: 0, translateY: contentTransitionMotion.rise, scale: 1 };\n case \"slide\": return { opacity: 0, translateX: (direction === \"rtl\" ? -1 : 1) * contentTransitionMotion.slide, translateY: 0, scale: 1 };\n case \"scale\": return { opacity: 0, translateX: 0, translateY: 0, scale: contentTransitionMotion.scale };\n default: throw new TypeError(\"Unsupported content transition preset\");\n }\n}\n\n/** Both rectangles must be measured in the same physical viewport coordinates.\n * Router shared-element IDs are not a substitute for a local overlay's geometry. */\nexport type TransitionRect = Readonly<{ x: number; y: number; width: number; height: number }>;\n\n/** Invert the destination around its center so it starts at the trigger bounds.\n * A renderer interpolates this transform to identity and owns cancellation,\n * measurement freshness, presence and focus; this resolver never clones content. */\nexport function resolveOriginTransition(\n origin: TransitionRect | null | undefined,\n destination: TransitionRect | null | undefined,\n reducedMotion = false,\n): Readonly<{ translateX: number; translateY: number; scaleX: number; scaleY: number }> | null {\n // Missing/zero geometry occurs before layout and after trigger removal. Keep\n // the canonical overlay available instead of throwing or guessing coordinates.\n if (reducedMotion || !origin || !destination) return null;\n for (const rect of [origin, destination]) {\n if (![rect.x, rect.y, rect.width, rect.height].every(Number.isFinite) || rect.width <= 0 || rect.height <= 0) return null;\n }\n const transform = {\n translateX: (origin.x - destination.x) + (origin.width - destination.width) / 2,\n translateY: (origin.y - destination.y) + (origin.height - destination.height) / 2,\n scaleX: origin.width / destination.width,\n scaleY: origin.height / destination.height,\n };\n // Finite measurements can still overflow or underflow during subtraction/division.\n return Object.values(transform).every(Number.isFinite) && transform.scaleX > 0 && transform.scaleY > 0 ? transform : null;\n}\n"]}
@@ -0,0 +1,71 @@
1
+ /** Experimental direct date entry contract; date calculation remains product-owned. */
2
+ export type DateEntryPart = "year" | "month" | "day";
3
+ export type DateEntryDraft = Readonly<Record<DateEntryPart, string>>;
4
+ export type DateEntryOrder = readonly [DateEntryPart, DateEntryPart, DateEntryPart];
5
+ export type DateEntryParseResult = Readonly<{
6
+ status: "valid";
7
+ value: string;
8
+ }> | Readonly<{
9
+ status: "incomplete" | "invalid";
10
+ code: string;
11
+ fields: readonly DateEntryPart[];
12
+ }>;
13
+ export type DateEntryIssue = Readonly<{
14
+ kind: "missing";
15
+ fields: readonly DateEntryPart[];
16
+ }> | Readonly<{
17
+ kind: "parse";
18
+ code: string;
19
+ fields: readonly DateEntryPart[];
20
+ }>;
21
+ export type ResolvedDateEntry = Readonly<{
22
+ draft: DateEntryDraft;
23
+ status: "empty" | "incomplete" | "invalid" | "valid";
24
+ /** An optional empty date and any uncommitted draft have no committed value. */
25
+ value: string | null;
26
+ issue: DateEntryIssue | null;
27
+ fields: readonly Readonly<{
28
+ part: DateEntryPart;
29
+ value: string;
30
+ invalid: boolean;
31
+ }>[];
32
+ }>;
33
+ /** Preserve exact input, including partial years, names, whitespace and composition text. */
34
+ export declare function updateDateEntryDraft(draft: DateEntryDraft, part: DateEntryPart, value: string): DateEntryDraft;
35
+ export declare function resolveDateEntryDraft({ draft, order, required, parse }: {
36
+ draft: DateEntryDraft;
37
+ order: DateEntryOrder;
38
+ required: boolean;
39
+ parse: (draft: DateEntryDraft) => DateEntryParseResult;
40
+ }): ResolvedDateEntry;
41
+ export type DateEntryControlProps = Readonly<{
42
+ value: DateEntryDraft;
43
+ onValueChange: (draft: DateEntryDraft) => void;
44
+ order: DateEntryOrder;
45
+ parse: (draft: DateEntryDraft) => DateEntryParseResult;
46
+ labels: Readonly<Record<DateEntryPart | "label", string>>;
47
+ formatIssue: (issue: DateEntryIssue) => string;
48
+ description?: string;
49
+ required?: boolean;
50
+ disabled?: boolean;
51
+ readOnly?: boolean;
52
+ /** Products reveal validation on submit/blur; typing never forces errors visible. */
53
+ showErrors?: boolean;
54
+ purpose?: "date" | "birthdate";
55
+ /** Text is the default so localized month names remain enterable. */
56
+ monthInput?: "text" | "numeric";
57
+ onBlur?: (part: DateEntryPart) => void;
58
+ }>;
59
+ export declare function resolveDateEntryControl(props: DateEntryControlProps): {
60
+ error: string | undefined;
61
+ draft: DateEntryDraft;
62
+ status: "empty" | "incomplete" | "invalid" | "valid";
63
+ value: string | null;
64
+ issue: DateEntryIssue | null;
65
+ fields: readonly Readonly<{
66
+ part: DateEntryPart;
67
+ value: string;
68
+ invalid: boolean;
69
+ }>[];
70
+ };
71
+ //# sourceMappingURL=date-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-entry.d.ts","sourceRoot":"","sources":["../src/date-entry.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AACrD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;AACrE,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AACpF,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C,QAAQ,CAAC;IAAE,MAAM,EAAE,YAAY,GAAG,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,CAAC,CAAC;AACnG,MAAM,MAAM,cAAc,GACtB,QAAQ,CAAC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,CAAC,GAC/D,QAAQ,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,CAAC,CAAC;AAChF,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;IACrD,gFAAgF;IAChF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,MAAM,EAAE,SAAS,QAAQ,CAAC;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,EAAE,CAAC;CACvF,CAAC,CAAC;AAcH,6FAA6F;AAC7F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAI9G;AAED,wBAAgB,qBAAqB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;IACvE,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,cAAc,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,oBAAoB,CAAC;CACxD,GAAG,iBAAiB,CAmCpB;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC3C,KAAK,EAAE,cAAc,CAAC;IACtB,aAAa,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,KAAK,EAAE,cAAc,CAAC;IACtB,KAAK,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,oBAAoB,CAAC;IACvD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,GAAG,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,MAAM,CAAC;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qFAAqF;IACrF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC/B,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACxC,CAAC,CAAC;AAEH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB;;WAxF3D,cAAc;YACb,OAAO,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO;WAE7C,MAAM,GAAG,IAAI;WACb,cAAc,GAAG,IAAI;YACpB,SAAS,QAAQ,CAAC;QAAE,IAAI,EAAE,aAAa,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,EAAE;EA8FtF"}
@@ -0,0 +1,78 @@
1
+ const parts = ["year", "month", "day"];
2
+ function assertDraft(draft) {
3
+ if (!draft || parts.some(part => typeof draft[part] !== "string")) {
4
+ throw new TypeError("Date entry requires string drafts for year, month and day");
5
+ }
6
+ }
7
+ function assertParts(values, complete = false) {
8
+ if (!Array.isArray(values) || !values.length || new Set(values).size !== values.length ||
9
+ values.some(part => !parts.includes(part)) || (complete && values.length !== 3)) {
10
+ throw new TypeError("Date entry requires distinct date parts and a complete display order");
11
+ }
12
+ }
13
+ /** Preserve exact input, including partial years, names, whitespace and composition text. */
14
+ export function updateDateEntryDraft(draft, part, value) {
15
+ assertDraft(draft);
16
+ if (!parts.includes(part) || typeof value !== "string")
17
+ throw new TypeError("Invalid date entry edit");
18
+ return { ...draft, [part]: value };
19
+ }
20
+ export function resolveDateEntryDraft({ draft, order, required, parse }) {
21
+ assertDraft(draft);
22
+ assertParts(order, true);
23
+ if (typeof required !== "boolean" || typeof parse !== "function")
24
+ throw new TypeError("Date entry requires required and parse policies");
25
+ // Calendar already leaves locale/calendar/clock policy to products. A second
26
+ // Date-based parser would normalize impossible dates and disagree with it.
27
+ // Freeze a snapshot so an adapter cannot rewrite the user's editing draft.
28
+ const snapshot = Object.freeze({ year: draft.year, month: draft.month, day: draft.day });
29
+ const missing = order.filter(part => !snapshot[part].trim());
30
+ let status;
31
+ let value = null;
32
+ let issue = null;
33
+ if (missing.length === 3) {
34
+ status = "empty";
35
+ if (required)
36
+ issue = { kind: "missing", fields: missing };
37
+ }
38
+ else if (missing.length) {
39
+ // Missing data takes priority over format/range errors, so filling one part
40
+ // cannot hide which other parts are still needed (GOV.UK date-input guidance).
41
+ status = "incomplete";
42
+ issue = { kind: "missing", fields: missing };
43
+ }
44
+ else {
45
+ const result = parse(snapshot);
46
+ if (result?.status === "valid") {
47
+ if (typeof result.value !== "string" || !result.value.trim())
48
+ throw new TypeError("A valid date entry needs a nonempty value");
49
+ status = "valid";
50
+ value = result.value;
51
+ }
52
+ else if (result?.status === "incomplete" || result?.status === "invalid") {
53
+ if (typeof result.code !== "string" || !result.code.trim())
54
+ throw new TypeError("Date entry issue needs a localization code");
55
+ assertParts(result.fields);
56
+ status = result.status;
57
+ issue = { kind: "parse", code: result.code, fields: order.filter(part => result.fields.includes(part)) };
58
+ }
59
+ else
60
+ throw new TypeError("Invalid date entry parse result");
61
+ }
62
+ return { draft: snapshot, status, value, issue,
63
+ fields: order.map(part => ({ part, value: snapshot[part], invalid: issue?.fields.includes(part) ?? false })) };
64
+ }
65
+ export function resolveDateEntryControl(props) {
66
+ if (["label", ...parts].some(key => !props.labels?.[key]?.trim()) ||
67
+ typeof props.onValueChange !== "function" || typeof props.formatIssue !== "function" ||
68
+ (props.purpose !== undefined && !["date", "birthdate"].includes(props.purpose)) ||
69
+ (props.monthInput !== undefined && !["text", "numeric"].includes(props.monthInput))) {
70
+ throw new TypeError("Date entry needs labels, callbacks and valid input policies");
71
+ }
72
+ const resolved = resolveDateEntryDraft({ draft: props.value, order: props.order, required: props.required ?? false, parse: props.parse });
73
+ const error = props.showErrors && resolved.issue ? props.formatIssue(resolved.issue) : undefined;
74
+ if (error !== undefined && (typeof error !== "string" || !error.trim()))
75
+ throw new TypeError("Date entry issue text must not be empty");
76
+ return { ...resolved, error };
77
+ }
78
+ //# sourceMappingURL=date-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-entry.js","sourceRoot":"","sources":["../src/date-entry.ts"],"names":[],"mappings":"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","sourcesContent":["/** Experimental direct date entry contract; date calculation remains product-owned. */\nexport type DateEntryPart = \"year\" | \"month\" | \"day\";\nexport type DateEntryDraft = Readonly<Record<DateEntryPart, string>>;\nexport type DateEntryOrder = readonly [DateEntryPart, DateEntryPart, DateEntryPart];\nexport type DateEntryParseResult =\n | Readonly<{ status: \"valid\"; value: string }>\n | Readonly<{ status: \"incomplete\" | \"invalid\"; code: string; fields: readonly DateEntryPart[] }>;\nexport type DateEntryIssue =\n | Readonly<{ kind: \"missing\"; fields: readonly DateEntryPart[] }>\n | Readonly<{ kind: \"parse\"; code: string; fields: readonly DateEntryPart[] }>;\nexport type ResolvedDateEntry = Readonly<{\n draft: DateEntryDraft;\n status: \"empty\" | \"incomplete\" | \"invalid\" | \"valid\";\n /** An optional empty date and any uncommitted draft have no committed value. */\n value: string | null;\n issue: DateEntryIssue | null;\n fields: readonly Readonly<{ part: DateEntryPart; value: string; invalid: boolean }>[];\n}>;\nconst parts: readonly DateEntryPart[] = [\"year\", \"month\", \"day\"];\nfunction assertDraft(draft: DateEntryDraft): void {\n if (!draft || parts.some(part => typeof draft[part] !== \"string\")) {\n throw new TypeError(\"Date entry requires string drafts for year, month and day\");\n }\n}\nfunction assertParts(values: readonly DateEntryPart[], complete = false): void {\n if (!Array.isArray(values) || !values.length || new Set(values).size !== values.length ||\n values.some(part => !parts.includes(part)) || (complete && values.length !== 3)) {\n throw new TypeError(\"Date entry requires distinct date parts and a complete display order\");\n }\n}\n\n/** Preserve exact input, including partial years, names, whitespace and composition text. */\nexport function updateDateEntryDraft(draft: DateEntryDraft, part: DateEntryPart, value: string): DateEntryDraft {\n assertDraft(draft);\n if (!parts.includes(part) || typeof value !== \"string\") throw new TypeError(\"Invalid date entry edit\");\n return { ...draft, [part]: value };\n}\n\nexport function resolveDateEntryDraft({ draft, order, required, parse }: {\n draft: DateEntryDraft;\n order: DateEntryOrder;\n required: boolean;\n parse: (draft: DateEntryDraft) => DateEntryParseResult;\n}): ResolvedDateEntry {\n assertDraft(draft);\n assertParts(order, true);\n if (typeof required !== \"boolean\" || typeof parse !== \"function\") throw new TypeError(\"Date entry requires required and parse policies\");\n // Calendar already leaves locale/calendar/clock policy to products. A second\n // Date-based parser would normalize impossible dates and disagree with it.\n // Freeze a snapshot so an adapter cannot rewrite the user's editing draft.\n const snapshot = Object.freeze({ year: draft.year, month: draft.month, day: draft.day });\n const missing = order.filter(part => !snapshot[part].trim());\n let status: ResolvedDateEntry[\"status\"];\n let value: string | null = null;\n let issue: DateEntryIssue | null = null;\n if (missing.length === 3) {\n status = \"empty\";\n if (required) issue = { kind: \"missing\", fields: missing };\n } else if (missing.length) {\n // Missing data takes priority over format/range errors, so filling one part\n // cannot hide which other parts are still needed (GOV.UK date-input guidance).\n status = \"incomplete\";\n issue = { kind: \"missing\", fields: missing };\n } else {\n const result = parse(snapshot);\n if (result?.status === \"valid\") {\n if (typeof result.value !== \"string\" || !result.value.trim()) throw new TypeError(\"A valid date entry needs a nonempty value\");\n status = \"valid\";\n value = result.value;\n } else if (result?.status === \"incomplete\" || result?.status === \"invalid\") {\n if (typeof result.code !== \"string\" || !result.code.trim()) throw new TypeError(\"Date entry issue needs a localization code\");\n assertParts(result.fields);\n status = result.status;\n issue = { kind: \"parse\", code: result.code, fields: order.filter(part => result.fields.includes(part)) };\n } else throw new TypeError(\"Invalid date entry parse result\");\n }\n return { draft: snapshot, status, value, issue,\n fields: order.map(part => ({ part, value: snapshot[part], invalid: issue?.fields.includes(part) ?? false })) };\n}\n\nexport type DateEntryControlProps = Readonly<{\n value: DateEntryDraft;\n onValueChange: (draft: DateEntryDraft) => void;\n order: DateEntryOrder;\n parse: (draft: DateEntryDraft) => DateEntryParseResult;\n labels: Readonly<Record<DateEntryPart | \"label\", string>>;\n formatIssue: (issue: DateEntryIssue) => string;\n description?: string;\n required?: boolean;\n disabled?: boolean;\n readOnly?: boolean;\n /** Products reveal validation on submit/blur; typing never forces errors visible. */\n showErrors?: boolean;\n purpose?: \"date\" | \"birthdate\";\n /** Text is the default so localized month names remain enterable. */\n monthInput?: \"text\" | \"numeric\";\n onBlur?: (part: DateEntryPart) => void;\n}>;\n\nexport function resolveDateEntryControl(props: DateEntryControlProps) {\n if ([\"label\", ...parts].some(key => !props.labels?.[key as keyof typeof props.labels]?.trim()) ||\n typeof props.onValueChange !== \"function\" || typeof props.formatIssue !== \"function\" ||\n (props.purpose !== undefined && ![\"date\", \"birthdate\"].includes(props.purpose)) ||\n (props.monthInput !== undefined && ![\"text\", \"numeric\"].includes(props.monthInput))) {\n throw new TypeError(\"Date entry needs labels, callbacks and valid input policies\");\n }\n const resolved = resolveDateEntryDraft({ draft: props.value, order: props.order, required: props.required ?? false, parse: props.parse });\n const error = props.showErrors && resolved.issue ? props.formatIssue(resolved.issue) : undefined;\n if (error !== undefined && (typeof error !== \"string\" || !error.trim())) throw new TypeError(\"Date entry issue text must not be empty\");\n return { ...resolved, error };\n}\n"]}
@@ -0,0 +1,104 @@
1
+ /** Candidate composition contract; file access, transfer and receipt verification stay with the host. */
2
+ export type DocumentPreviewState = Readonly<{
3
+ status: "none" | "loading" | "ready";
4
+ }> | Readonly<{
5
+ status: "error";
6
+ message: string;
7
+ retryable: boolean;
8
+ }>;
9
+ export type DocumentSaveState = Readonly<{
10
+ status: "idle" | "pending" | "started" | "saved" | "cancelled";
11
+ }> | Readonly<{
12
+ status: "error";
13
+ message: string;
14
+ retryable: boolean;
15
+ }>;
16
+ export type DocumentResourceDescriptor = Readonly<{
17
+ /** Include a revision when reusing a resource id for different file contents. */
18
+ id: string;
19
+ name: string;
20
+ formatLabel?: string;
21
+ sizeLabel?: string;
22
+ description?: string;
23
+ disabled?: boolean;
24
+ /** Product review/permission gates may block export while keeping preview accessible. */
25
+ saveDisabled?: boolean;
26
+ preview: DocumentPreviewState;
27
+ save: DocumentSaveState;
28
+ }>;
29
+ export type DocumentResourceLabels = Readonly<{
30
+ preview: string;
31
+ previewLoading: string;
32
+ previewUnavailable: string;
33
+ retryPreview: string;
34
+ save: string;
35
+ saving: string;
36
+ started: string;
37
+ saved: string;
38
+ cancelled: string;
39
+ retrySave: string;
40
+ }>;
41
+ export type DocumentResourceControls = Readonly<{
42
+ descriptor: DocumentResourceDescriptor;
43
+ labels: DocumentResourceLabels;
44
+ onPreview?: () => void;
45
+ onRetryPreview?: () => void;
46
+ onSave: () => void;
47
+ onRetrySave?: () => void;
48
+ }>;
49
+ /** Controlled UI only: hosts connect the existing action session to their verified results. */
50
+ export declare function resolveDocumentResourceControls(props: DocumentResourceControls): Readonly<{
51
+ id: string;
52
+ name: string;
53
+ metadata: readonly string[];
54
+ description: string | undefined;
55
+ disabled: boolean;
56
+ saveDisabled: boolean;
57
+ preview: Readonly<{
58
+ status: "none" | "loading" | "ready";
59
+ } | {
60
+ status: "error";
61
+ message: string;
62
+ retryable: boolean;
63
+ }>;
64
+ save: Readonly<{
65
+ status: "idle" | "pending" | "started" | "saved" | "cancelled";
66
+ } | {
67
+ status: "error";
68
+ message: string;
69
+ retryable: boolean;
70
+ }>;
71
+ canPreview: boolean;
72
+ canRetryPreview: boolean;
73
+ canSave: boolean;
74
+ canRetrySave: boolean;
75
+ saved: boolean;
76
+ }>;
77
+ export declare function resolveDocumentResource(descriptor: DocumentResourceDescriptor): Readonly<{
78
+ id: string;
79
+ name: string;
80
+ metadata: readonly string[];
81
+ description: string | undefined;
82
+ disabled: boolean;
83
+ saveDisabled: boolean;
84
+ preview: Readonly<{
85
+ status: "none" | "loading" | "ready";
86
+ } | {
87
+ status: "error";
88
+ message: string;
89
+ retryable: boolean;
90
+ }>;
91
+ save: Readonly<{
92
+ status: "idle" | "pending" | "started" | "saved" | "cancelled";
93
+ } | {
94
+ status: "error";
95
+ message: string;
96
+ retryable: boolean;
97
+ }>;
98
+ canPreview: boolean;
99
+ canRetryPreview: boolean;
100
+ canSave: boolean;
101
+ canRetrySave: boolean;
102
+ saved: boolean;
103
+ }>;
104
+ //# sourceMappingURL=document-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-resource.d.ts","sourceRoot":"","sources":["../src/document-resource.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAA;CAAE,CAAC,GAClD,QAAQ,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEvE,MAAM,MAAM,iBAAiB,GACzB,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,CAAA;CAAE,CAAC,GAC5E,QAAQ,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CAAC;AAEvE,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yFAAyF;IACzF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,IAAI,EAAE,iBAAiB,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,UAAU,EAAE,0BAA0B,CAAC;IACvC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,CAAC,CAAC;AAEH,+FAA+F;AAC/F,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,wBAAwB;;;;;;;;gBA5CxD,MAAM,GAAG,SAAS,GAAG,OAAO;;gBAC5B,OAAO;iBAAW,MAAM;mBAAa,OAAO;;;gBAG5C,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW;;gBACtD,OAAO;iBAAW,MAAM;mBAAa,OAAO;;;;;;;GAmDlE;AAmBD,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,0BAA0B;;;;;;;;gBA3EvD,MAAM,GAAG,SAAS,GAAG,OAAO;;gBAC5B,OAAO;iBAAW,MAAM;mBAAa,OAAO;;;gBAG5C,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW;;gBACtD,OAAO;iBAAW,MAAM;mBAAa,OAAO;;;;;;;GA6GlE"}