@cratis/scene.primereact 4.4.0 → 4.6.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 (156) hide show
  1. package/README.md +25 -3
  2. package/chart/ChartGallery.stories.tsx +63 -0
  3. package/chart/ChartType.ts +14 -0
  4. package/chart/ChartTypeResolution.ts +14 -0
  5. package/chart/PrimeChart.tsx +62 -0
  6. package/chart/chartHasData.ts +22 -0
  7. package/chart/chartTypeChoices.ts +32 -0
  8. package/chart/index.ts +7 -0
  9. package/chart/resolveChartType.ts +61 -0
  10. package/chart/useChart.ts +61 -0
  11. package/dist/cjs/chart/ChartType.js +18 -0
  12. package/dist/cjs/chart/ChartType.js.map +1 -0
  13. package/dist/cjs/chart/PrimeChart.js +92 -0
  14. package/dist/cjs/chart/PrimeChart.js.map +1 -0
  15. package/dist/cjs/chart/chartHasData.js +24 -0
  16. package/dist/cjs/chart/chartHasData.js.map +1 -0
  17. package/dist/cjs/chart/chartTypeChoices.js +43 -0
  18. package/dist/cjs/chart/chartTypeChoices.js.map +1 -0
  19. package/dist/cjs/chart/resolveChartType.js +69 -0
  20. package/dist/cjs/chart/resolveChartType.js.map +1 -0
  21. package/dist/cjs/chart/useChart.js +62 -0
  22. package/dist/cjs/chart/useChart.js.map +1 -0
  23. package/dist/cjs/form/MultiStateGlyph.js +59 -0
  24. package/dist/cjs/form/MultiStateGlyph.js.map +1 -0
  25. package/dist/cjs/form/PrimeMultiStateCheckbox.js +123 -0
  26. package/dist/cjs/form/PrimeMultiStateCheckbox.js.map +1 -0
  27. package/dist/cjs/form/multiStateOptions.js +77 -0
  28. package/dist/cjs/form/multiStateOptions.js.map +1 -0
  29. package/dist/cjs/form/multiStateStates.js +32 -0
  30. package/dist/cjs/form/multiStateStates.js.map +1 -0
  31. package/dist/cjs/form/useMultiStateSelection.js +51 -0
  32. package/dist/cjs/form/useMultiStateSelection.js.map +1 -0
  33. package/dist/cjs/index.js +12 -0
  34. package/dist/cjs/index.js.map +1 -1
  35. package/dist/cjs/primeReactComponents.js +5 -0
  36. package/dist/cjs/primeReactComponents.js.map +1 -1
  37. package/dist/cjs/primeReactDescriptors.js +157 -0
  38. package/dist/cjs/primeReactDescriptors.js.map +1 -0
  39. package/dist/cjs/primeReactPackage.js +4 -0
  40. package/dist/cjs/primeReactPackage.js.map +1 -1
  41. package/dist/cjs/properties.js +11 -0
  42. package/dist/cjs/properties.js.map +1 -1
  43. package/dist/cjs/structurallyEqual.js +27 -0
  44. package/dist/cjs/structurallyEqual.js.map +1 -0
  45. package/dist/cjs/useStructuralValue.js +20 -0
  46. package/dist/cjs/useStructuralValue.js.map +1 -0
  47. package/dist/esm/chart/ChartGallery.stories.d.ts +14 -0
  48. package/dist/esm/chart/ChartGallery.stories.d.ts.map +1 -0
  49. package/dist/esm/chart/ChartGallery.stories.js +47 -0
  50. package/dist/esm/chart/ChartGallery.stories.js.map +1 -0
  51. package/dist/esm/chart/ChartType.d.ts +11 -0
  52. package/dist/esm/chart/ChartType.d.ts.map +1 -0
  53. package/dist/esm/chart/ChartType.js +16 -0
  54. package/dist/esm/chart/ChartType.js.map +1 -0
  55. package/dist/esm/chart/ChartTypeResolution.d.ts +10 -0
  56. package/dist/esm/chart/ChartTypeResolution.d.ts.map +1 -0
  57. package/dist/esm/chart/ChartTypeResolution.js +2 -0
  58. package/dist/esm/chart/ChartTypeResolution.js.map +1 -0
  59. package/dist/esm/chart/PrimeChart.d.ts +3 -0
  60. package/dist/esm/chart/PrimeChart.d.ts.map +1 -0
  61. package/dist/esm/chart/PrimeChart.js +90 -0
  62. package/dist/esm/chart/PrimeChart.js.map +1 -0
  63. package/dist/esm/chart/chartHasData.d.ts +2 -0
  64. package/dist/esm/chart/chartHasData.d.ts.map +1 -0
  65. package/dist/esm/chart/chartHasData.js +22 -0
  66. package/dist/esm/chart/chartHasData.js.map +1 -0
  67. package/dist/esm/chart/chartTypeChoices.d.ts +3 -0
  68. package/dist/esm/chart/chartTypeChoices.d.ts.map +1 -0
  69. package/dist/esm/chart/chartTypeChoices.js +41 -0
  70. package/dist/esm/chart/chartTypeChoices.js.map +1 -0
  71. package/dist/esm/chart/index.d.ts +5 -0
  72. package/dist/esm/chart/index.d.ts.map +1 -0
  73. package/dist/esm/chart/index.js +5 -0
  74. package/dist/esm/chart/index.js.map +1 -0
  75. package/dist/esm/chart/resolveChartType.d.ts +6 -0
  76. package/dist/esm/chart/resolveChartType.d.ts.map +1 -0
  77. package/dist/esm/chart/resolveChartType.js +66 -0
  78. package/dist/esm/chart/resolveChartType.js.map +1 -0
  79. package/dist/esm/chart/useChart.d.ts +4 -0
  80. package/dist/esm/chart/useChart.d.ts.map +1 -0
  81. package/dist/esm/chart/useChart.js +60 -0
  82. package/dist/esm/chart/useChart.js.map +1 -0
  83. package/dist/esm/form/FormGallery.stories.d.ts.map +1 -1
  84. package/dist/esm/form/FormGallery.stories.js +8 -0
  85. package/dist/esm/form/FormGallery.stories.js.map +1 -1
  86. package/dist/esm/form/MultiStateGlyph.d.ts +8 -0
  87. package/dist/esm/form/MultiStateGlyph.d.ts.map +1 -0
  88. package/dist/esm/form/MultiStateGlyph.js +57 -0
  89. package/dist/esm/form/MultiStateGlyph.js.map +1 -0
  90. package/dist/esm/form/MultiStateOption.d.ts +7 -0
  91. package/dist/esm/form/MultiStateOption.d.ts.map +1 -0
  92. package/dist/esm/form/MultiStateOption.js +2 -0
  93. package/dist/esm/form/MultiStateOption.js.map +1 -0
  94. package/dist/esm/form/PrimeMultiStateCheckbox.d.ts +3 -0
  95. package/dist/esm/form/PrimeMultiStateCheckbox.d.ts.map +1 -0
  96. package/dist/esm/form/PrimeMultiStateCheckbox.js +121 -0
  97. package/dist/esm/form/PrimeMultiStateCheckbox.js.map +1 -0
  98. package/dist/esm/form/index.d.ts +1 -0
  99. package/dist/esm/form/index.d.ts.map +1 -1
  100. package/dist/esm/form/index.js +1 -0
  101. package/dist/esm/form/index.js.map +1 -1
  102. package/dist/esm/form/multiStateOptions.d.ts +4 -0
  103. package/dist/esm/form/multiStateOptions.d.ts.map +1 -0
  104. package/dist/esm/form/multiStateOptions.js +75 -0
  105. package/dist/esm/form/multiStateOptions.js.map +1 -0
  106. package/dist/esm/form/multiStateStates.d.ts +4 -0
  107. package/dist/esm/form/multiStateStates.d.ts.map +1 -0
  108. package/dist/esm/form/multiStateStates.js +30 -0
  109. package/dist/esm/form/multiStateStates.js.map +1 -0
  110. package/dist/esm/form/useMultiStateSelection.d.ts +6 -0
  111. package/dist/esm/form/useMultiStateSelection.d.ts.map +1 -0
  112. package/dist/esm/form/useMultiStateSelection.js +49 -0
  113. package/dist/esm/form/useMultiStateSelection.js.map +1 -0
  114. package/dist/esm/index.d.ts +2 -0
  115. package/dist/esm/index.d.ts.map +1 -1
  116. package/dist/esm/index.js +6 -1
  117. package/dist/esm/index.js.map +1 -1
  118. package/dist/esm/primeReactComponents.d.ts.map +1 -1
  119. package/dist/esm/primeReactComponents.js +5 -0
  120. package/dist/esm/primeReactComponents.js.map +1 -1
  121. package/dist/esm/primeReactDescriptors.d.ts +3 -0
  122. package/dist/esm/primeReactDescriptors.d.ts.map +1 -0
  123. package/dist/esm/primeReactDescriptors.js +155 -0
  124. package/dist/esm/primeReactDescriptors.js.map +1 -0
  125. package/dist/esm/primeReactPackage.d.ts.map +1 -1
  126. package/dist/esm/primeReactPackage.js +4 -0
  127. package/dist/esm/primeReactPackage.js.map +1 -1
  128. package/dist/esm/properties.d.ts +1 -0
  129. package/dist/esm/properties.d.ts.map +1 -1
  130. package/dist/esm/properties.js +11 -1
  131. package/dist/esm/properties.js.map +1 -1
  132. package/dist/esm/structurallyEqual.d.ts +2 -0
  133. package/dist/esm/structurallyEqual.d.ts.map +1 -0
  134. package/dist/esm/structurallyEqual.js +25 -0
  135. package/dist/esm/structurallyEqual.js.map +1 -0
  136. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  137. package/dist/esm/useStructuralValue.d.ts +2 -0
  138. package/dist/esm/useStructuralValue.d.ts.map +1 -0
  139. package/dist/esm/useStructuralValue.js +18 -0
  140. package/dist/esm/useStructuralValue.js.map +1 -0
  141. package/form/FormGallery.stories.tsx +8 -0
  142. package/form/MultiStateGlyph.tsx +55 -0
  143. package/form/MultiStateOption.ts +17 -0
  144. package/form/PrimeMultiStateCheckbox.tsx +101 -0
  145. package/form/index.ts +1 -0
  146. package/form/multiStateOptions.ts +78 -0
  147. package/form/multiStateStates.ts +23 -0
  148. package/form/useMultiStateSelection.ts +48 -0
  149. package/index.ts +2 -0
  150. package/package.json +17 -7
  151. package/primeReactComponents.ts +4 -0
  152. package/primeReactDescriptors.ts +48 -0
  153. package/primeReactPackage.ts +4 -2
  154. package/properties.ts +14 -0
  155. package/structurallyEqual.ts +29 -0
  156. package/useStructuralValue.ts +17 -0
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ var ChartType = require('./ChartType.js');
4
+
5
+ // Copyright (c) Cratis. All rights reserved.
6
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
7
+ /**
8
+ * The ordinals of the original .NET `PrimeReact.Charts.ChartType` enum, in declaration order
9
+ * (`Studio/Source/PrimeReact/Charts/Chart.cs`). Migrated documents keep the ordinal, so the position of
10
+ * each entry here is part of the stored-data contract and must never be reordered.
11
+ */ const legacyChartTypes = [
12
+ ChartType.ChartType.Bar,
13
+ ChartType.ChartType.Line,
14
+ ChartType.ChartType.Pie,
15
+ ChartType.ChartType.Doughnut,
16
+ ChartType.ChartType.PolarArea,
17
+ ChartType.ChartType.Radar,
18
+ ChartType.ChartType.Bubble,
19
+ ChartType.ChartType.Scatter
20
+ ];
21
+ /**
22
+ * Resolves an authored chart type to the Chart.js vocabulary.
23
+ *
24
+ * Three forms are accepted, and the stored value is never rewritten:
25
+ * - a canonical Chart.js name from {@link ChartType} (`'polarArea'`), which new documents use;
26
+ * - the ordinal of the original .NET enum (`4`), which migrated documents carry;
27
+ * - the .NET member name in its original Pascal case (`'PolarArea'`), which a JSON serialization of that
28
+ * enum produces.
29
+ *
30
+ * Anything else - an unknown or fractional ordinal, a numeric string, a differently cased name, `null` -
31
+ * resolves to a finding with a message, because the right chart cannot be known. An absent `type` is the
32
+ * one default: the original control defaulted to `Bar`.
33
+ */ function resolveChartType(element) {
34
+ const value = element.properties.type;
35
+ if (value === undefined) return {
36
+ isValid: true,
37
+ type: ChartType.ChartType.Bar
38
+ };
39
+ if (typeof value === 'number') {
40
+ const type = Number.isInteger(value) ? legacyChartTypes[value] : undefined;
41
+ return type === undefined ? unsupported(value) : {
42
+ isValid: true,
43
+ type
44
+ };
45
+ }
46
+ if (typeof value === 'string') {
47
+ if (Object.values(ChartType.ChartType).includes(value)) return {
48
+ isValid: true,
49
+ type: value
50
+ };
51
+ if (Object.hasOwn(ChartType.ChartType, value)) return {
52
+ isValid: true,
53
+ type: ChartType.ChartType[value]
54
+ };
55
+ }
56
+ return unsupported(value);
57
+ }
58
+ function unsupported(value) {
59
+ const shown = typeof value === 'string' ? `'${value}'` : JSON.stringify(value) ?? String(value);
60
+ return {
61
+ isValid: false,
62
+ value,
63
+ message: `Unsupported chart type ${shown}. Use one of ${Object.values(ChartType.ChartType).join(', ')}, or a legacy ordinal from 0 to ${legacyChartTypes.length - 1}.`
64
+ };
65
+ }
66
+
67
+ exports.legacyChartTypes = legacyChartTypes;
68
+ exports.resolveChartType = resolveChartType;
69
+ //# sourceMappingURL=resolveChartType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveChartType.js","sources":["../../../chart/resolveChartType.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { SceneElement } from '@cratis/scene.model';\nimport { ChartType } from './ChartType';\nimport { ChartTypeResolution } from './ChartTypeResolution';\n\n/**\n * The ordinals of the original .NET `PrimeReact.Charts.ChartType` enum, in declaration order\n * (`Studio/Source/PrimeReact/Charts/Chart.cs`). Migrated documents keep the ordinal, so the position of\n * each entry here is part of the stored-data contract and must never be reordered.\n */\nexport const legacyChartTypes: readonly ChartType[] = [\n ChartType.Bar,\n ChartType.Line,\n ChartType.Pie,\n ChartType.Doughnut,\n ChartType.PolarArea,\n ChartType.Radar,\n ChartType.Bubble,\n ChartType.Scatter,\n];\n\n/**\n * Resolves an authored chart type to the Chart.js vocabulary.\n *\n * Three forms are accepted, and the stored value is never rewritten:\n * - a canonical Chart.js name from {@link ChartType} (`'polarArea'`), which new documents use;\n * - the ordinal of the original .NET enum (`4`), which migrated documents carry;\n * - the .NET member name in its original Pascal case (`'PolarArea'`), which a JSON serialization of that\n * enum produces.\n *\n * Anything else - an unknown or fractional ordinal, a numeric string, a differently cased name, `null` -\n * resolves to a finding with a message, because the right chart cannot be known. An absent `type` is the\n * one default: the original control defaulted to `Bar`.\n */\nexport function resolveChartType(element: SceneElement): ChartTypeResolution {\n const value = element.properties.type;\n if (value === undefined) return { isValid: true, type: ChartType.Bar };\n\n if (typeof value === 'number') {\n const type = Number.isInteger(value) ? legacyChartTypes[value] : undefined;\n return type === undefined ? unsupported(value) : { isValid: true, type };\n }\n\n if (typeof value === 'string') {\n if (Object.values(ChartType).includes(value as ChartType)) return { isValid: true, type: value as ChartType };\n if (Object.hasOwn(ChartType, value)) return { isValid: true, type: ChartType[value as keyof typeof ChartType] };\n }\n\n return unsupported(value);\n}\n\nfunction unsupported(value: unknown): ChartTypeResolution {\n const shown = typeof value === 'string' ? `'${value}'` : JSON.stringify(value) ?? String(value);\n return {\n isValid: false,\n value,\n message: `Unsupported chart type ${shown}. Use one of ${Object.values(ChartType).join(', ')}, or a legacy ordinal from 0 to ${legacyChartTypes.length - 1}.`,\n };\n}\n"],"names":["legacyChartTypes","ChartType","Bar","Line","Pie","Doughnut","PolarArea","Radar","Bubble","Scatter","resolveChartType","element","value","properties","type","undefined","isValid","Number","isInteger","unsupported","Object","values","includes","hasOwn","shown","JSON","stringify","String","message","join","length"],"mappings":";;;;AAAA;AACA;AAMA;;;;UAKaA,gBAAAA,GAAyC;AAClDC,IAAAA,mBAAAA,CAAUC,GAAG;AACbD,IAAAA,mBAAAA,CAAUE,IAAI;AACdF,IAAAA,mBAAAA,CAAUG,GAAG;AACbH,IAAAA,mBAAAA,CAAUI,QAAQ;AAClBJ,IAAAA,mBAAAA,CAAUK,SAAS;AACnBL,IAAAA,mBAAAA,CAAUM,KAAK;AACfN,IAAAA,mBAAAA,CAAUO,MAAM;AAChBP,IAAAA,mBAAAA,CAAUQ;;AAGd;;;;;;;;;;;;IAaO,SAASC,gBAAAA,CAAiBC,OAAqB,EAAA;AAClD,IAAA,MAAMC,KAAAA,GAAQD,OAAAA,CAAQE,UAAU,CAACC,IAAI;IACrC,IAAIF,KAAAA,KAAUG,WAAW,OAAO;QAAEC,OAAAA,EAAS,IAAA;AAAMF,QAAAA,IAAAA,EAAMb,oBAAUC;AAAI,KAAA;IAErE,IAAI,OAAOU,UAAU,QAAA,EAAU;QAC3B,MAAME,IAAAA,GAAOG,OAAOC,SAAS,CAACN,SAASZ,gBAAgB,CAACY,MAAM,GAAGG,SAAAA;QACjE,OAAOD,IAAAA,KAASC,SAAAA,GAAYI,WAAAA,CAAYP,KAAAA,CAAAA,GAAS;YAAEI,OAAAA,EAAS,IAAA;AAAMF,YAAAA;AAAK,SAAA;AAC3E,IAAA;IAEA,IAAI,OAAOF,UAAU,QAAA,EAAU;AAC3B,QAAA,IAAIQ,OAAOC,MAAM,CAACpB,qBAAWqB,QAAQ,CAACV,QAAqB,OAAO;YAAEI,OAAAA,EAAS,IAAA;YAAMF,IAAAA,EAAMF;AAAmB,SAAA;AAC5G,QAAA,IAAIQ,MAAAA,CAAOG,MAAM,CAACtB,mBAAAA,EAAWW,QAAQ,OAAO;YAAEI,OAAAA,EAAS,IAAA;YAAMF,IAAAA,EAAMb,mBAAS,CAACW,KAAAA;AAAiC,SAAA;AAClH,IAAA;AAEA,IAAA,OAAOO,WAAAA,CAAYP,KAAAA,CAAAA;AACvB;AAEA,SAASO,YAAYP,KAAc,EAAA;AAC/B,IAAA,MAAMY,KAAAA,GAAQ,OAAOZ,KAAAA,KAAU,QAAA,GAAW,CAAC,CAAC,EAAEA,KAAAA,CAAM,CAAC,CAAC,GAAGa,IAAAA,CAAKC,SAAS,CAACd,UAAUe,MAAAA,CAAOf,KAAAA,CAAAA;IACzF,OAAO;QACHI,OAAAA,EAAS,KAAA;AACTJ,QAAAA,KAAAA;QACAgB,OAAAA,EAAS,CAAC,uBAAuB,EAAEJ,KAAAA,CAAM,aAAa,EAAEJ,MAAAA,CAAOC,MAAM,CAACpB,mBAAAA,CAAAA,CAAW4B,IAAI,CAAC,IAAA,CAAA,CAAM,gCAAgC,EAAE7B,gBAAAA,CAAiB8B,MAAM,GAAG,CAAA,CAAE,CAAC;AAC/J,KAAA;AACJ;;;"}
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // Copyright (c) Cratis. All rights reserved.
6
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
7
+ /**
8
+ * Draws a Chart.js chart on a canvas and owns its lifetime.
9
+ *
10
+ * Chart.js loads only after the canvas has mounted, which keeps server rendering independent of browser
11
+ * globals. The chart is destroyed before it is rebuilt and when the component unmounts - Chart.js owns
12
+ * listeners and resize observers, so a retained instance would draw twice and leak them.
13
+ *
14
+ * A chart that cannot be drawn is reported rather than left as a blank canvas: `chart.js` not being
15
+ * installed (it is an optional peer dependency), a failed dynamic import and a rejected configuration all
16
+ * come back as the returned failure message. A rejected configuration is released from the canvas as well,
17
+ * so correcting it draws again on the same canvas.
18
+ *
19
+ * @param canvas The canvas to draw on. It must be rendered whenever `enabled` is true.
20
+ * @param configuration The Chart.js configuration. Pass a structurally stable value (see
21
+ * {@link useStructuralValue}); a new identity rebuilds the chart.
22
+ * @param enabled Whether there is something to draw.
23
+ * @returns The reason the chart could not be drawn, or `undefined`.
24
+ */ function useChart(canvas, configuration, enabled) {
25
+ const [failure, setFailure] = react.useState(undefined);
26
+ react.useEffect(()=>{
27
+ setFailure(undefined);
28
+ const target = canvas.current;
29
+ if (!enabled || target === null) return undefined;
30
+ let disposed = false;
31
+ let instance;
32
+ const create = async ()=>{
33
+ let chartType;
34
+ try {
35
+ chartType = (await import('chart.js/auto')).default;
36
+ if (disposed) return;
37
+ instance = new chartType(target, structuredClone(configuration));
38
+ } catch (error) {
39
+ // Chart.js registers a chart on its canvas before the constructor finishes, so a constructor
40
+ // that throws still leaves a registered instance behind - one `instance` never points at. Left
41
+ // alone it makes every later attempt fail with "Canvas is already in use" and hides the real
42
+ // reason, so release whatever is bound to this canvas before reporting.
43
+ chartType?.getChart(target)?.destroy();
44
+ if (!disposed) setFailure(error instanceof Error ? error.message : String(error));
45
+ }
46
+ };
47
+ void create();
48
+ return ()=>{
49
+ disposed = true;
50
+ instance?.destroy();
51
+ instance = undefined;
52
+ };
53
+ }, [
54
+ canvas,
55
+ configuration,
56
+ enabled
57
+ ]);
58
+ return failure;
59
+ }
60
+
61
+ exports.useChart = useChart;
62
+ //# sourceMappingURL=useChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useChart.js","sources":["../../../chart/useChart.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { RefObject, useEffect, useState } from 'react';\nimport type { ChartConfiguration } from 'chart.js';\n\n/**\n * Draws a Chart.js chart on a canvas and owns its lifetime.\n *\n * Chart.js loads only after the canvas has mounted, which keeps server rendering independent of browser\n * globals. The chart is destroyed before it is rebuilt and when the component unmounts - Chart.js owns\n * listeners and resize observers, so a retained instance would draw twice and leak them.\n *\n * A chart that cannot be drawn is reported rather than left as a blank canvas: `chart.js` not being\n * installed (it is an optional peer dependency), a failed dynamic import and a rejected configuration all\n * come back as the returned failure message. A rejected configuration is released from the canvas as well,\n * so correcting it draws again on the same canvas.\n *\n * @param canvas The canvas to draw on. It must be rendered whenever `enabled` is true.\n * @param configuration The Chart.js configuration. Pass a structurally stable value (see\n * {@link useStructuralValue}); a new identity rebuilds the chart.\n * @param enabled Whether there is something to draw.\n * @returns The reason the chart could not be drawn, or `undefined`.\n */\nexport function useChart(canvas: RefObject<HTMLCanvasElement | null>, configuration: ChartConfiguration, enabled: boolean): string | undefined {\n const [failure, setFailure] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n setFailure(undefined);\n const target = canvas.current;\n if (!enabled || target === null) return undefined;\n\n let disposed = false;\n let instance: { destroy(): void } | undefined;\n\n const create = async () => {\n let chartType: typeof import('chart.js/auto').default | undefined;\n try {\n chartType = (await import('chart.js/auto')).default;\n if (disposed) return;\n instance = new chartType(target, structuredClone(configuration));\n } catch (error) {\n // Chart.js registers a chart on its canvas before the constructor finishes, so a constructor\n // that throws still leaves a registered instance behind - one `instance` never points at. Left\n // alone it makes every later attempt fail with \"Canvas is already in use\" and hides the real\n // reason, so release whatever is bound to this canvas before reporting.\n chartType?.getChart(target)?.destroy();\n if (!disposed) setFailure(error instanceof Error ? error.message : String(error));\n }\n };\n\n void create();\n return () => {\n disposed = true;\n instance?.destroy();\n instance = undefined;\n };\n }, [canvas, configuration, enabled]);\n\n return failure;\n}\n"],"names":["useChart","canvas","configuration","enabled","failure","setFailure","useState","undefined","useEffect","target","current","disposed","instance","create","chartType","default","structuredClone","error","getChart","destroy","Error","message","String"],"mappings":";;;;AAAA;AACA;AAKA;;;;;;;;;;;;;;;;;AAiBC,IACM,SAASA,QAAAA,CAASC,MAA2C,EAAEC,aAAiC,EAAEC,OAAgB,EAAA;AACrH,IAAA,MAAM,CAACC,OAAAA,EAASC,UAAAA,CAAW,GAAGC,cAAAA,CAA6BC,SAAAA,CAAAA;IAE3DC,eAAAA,CAAU,IAAA;QACNH,UAAAA,CAAWE,SAAAA,CAAAA;QACX,MAAME,MAAAA,GAASR,OAAOS,OAAO;AAC7B,QAAA,IAAI,CAACP,OAAAA,IAAWM,MAAAA,KAAW,IAAA,EAAM,OAAOF,SAAAA;AAExC,QAAA,IAAII,QAAAA,GAAW,KAAA;QACf,IAAIC,QAAAA;AAEJ,QAAA,MAAMC,MAAAA,GAAS,UAAA;YACX,IAAIC,SAAAA;YACJ,IAAI;AACAA,gBAAAA,SAAAA,GAAY,CAAC,MAAM,OAAO,eAAA,CAAe,EAAGC,OAAO;AACnD,gBAAA,IAAIJ,QAAAA,EAAU;gBACdC,QAAAA,GAAW,IAAIE,SAAAA,CAAUL,MAAAA,EAAQO,eAAAA,CAAgBd,aAAAA,CAAAA,CAAAA;AACrD,YAAA,CAAA,CAAE,OAAOe,KAAAA,EAAO;;;;;AAKZH,gBAAAA,SAAAA,EAAWI,SAAST,MAAAA,CAAAA,EAASU,OAAAA,EAAAA;gBAC7B,IAAI,CAACR,UAAUN,UAAAA,CAAWY,KAAAA,YAAiBG,QAAQH,KAAAA,CAAMI,OAAO,GAAGC,MAAAA,CAAOL,KAAAA,CAAAA,CAAAA;AAC9E,YAAA;AACJ,QAAA,CAAA;QAEA,KAAKJ,MAAAA,EAAAA;QACL,OAAO,IAAA;YACHF,QAAAA,GAAW,IAAA;YACXC,QAAAA,EAAUO,OAAAA,EAAAA;YACVP,QAAAA,GAAWL,SAAAA;AACf,QAAA,CAAA;IACJ,CAAA,EAAG;AAACN,QAAAA,MAAAA;AAAQC,QAAAA,aAAAA;AAAeC,QAAAA;AAAQ,KAAA,CAAA;IAEnC,OAAOC,OAAAA;AACX;;"}
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var scene_react = require('@cratis/scene.react');
5
+
6
+ /**
7
+ * The box a multi-state checkbox draws, themed with the PrimeReact checkbox tokens (`--p-checkbox-*`), so
8
+ * it follows the active Scene theme and looks like its sibling `checkbox`. It holds the state's icon - a
9
+ * PrimeIcons class or a qualified icon reference - or a check mark when the state has no icon of its own.
10
+ * An empty state draws only its own icon, if it has one. It is decorative: the state is announced through the control's text, not through this glyph.
11
+ */ function MultiStateGlyph({ state, isEmpty, isInactive }) {
12
+ const icon = state?.icon;
13
+ return /*#__PURE__*/ jsxRuntime.jsx("span", {
14
+ "aria-hidden": "true",
15
+ "data-scene-part": "glyph",
16
+ style: {
17
+ display: 'inline-flex',
18
+ alignItems: 'center',
19
+ justifyContent: 'center',
20
+ flexShrink: 0,
21
+ boxSizing: 'border-box',
22
+ width: 'var(--p-checkbox-width, 1.125rem)',
23
+ height: 'var(--p-checkbox-height, 1.125rem)',
24
+ borderRadius: 'var(--p-checkbox-border-radius, 4px)',
25
+ border: `1px solid ${isEmpty ? 'var(--p-checkbox-border-color, currentColor)' : 'var(--p-checkbox-checked-border-color, currentColor)'}`,
26
+ backgroundColor: isEmpty ? 'var(--p-checkbox-background, transparent)' : 'var(--p-checkbox-checked-background, currentColor)',
27
+ color: glyphColor(isEmpty, isInactive),
28
+ fontSize: 'var(--p-checkbox-icon-size, 0.75rem)'
29
+ },
30
+ children: icon === undefined ? !isEmpty && /*#__PURE__*/ jsxRuntime.jsx(CheckMark, {}) : typeof icon === 'string' ? /*#__PURE__*/ jsxRuntime.jsx("i", {
31
+ className: icon
32
+ }) : /*#__PURE__*/ jsxRuntime.jsx(scene_react.SceneIcon, {
33
+ reference: icon,
34
+ size: "var(--p-checkbox-icon-size, 0.75rem)"
35
+ })
36
+ });
37
+ }
38
+ function glyphColor(isEmpty, isInactive) {
39
+ if (isInactive) return 'var(--p-checkbox-icon-disabled-color, currentColor)';
40
+ return isEmpty ? 'var(--p-checkbox-icon-color, currentColor)' : 'var(--p-checkbox-icon-checked-color, Canvas)';
41
+ }
42
+ function CheckMark() {
43
+ return /*#__PURE__*/ jsxRuntime.jsx("svg", {
44
+ viewBox: "0 0 12 12",
45
+ width: "1em",
46
+ height: "1em",
47
+ fill: "none",
48
+ stroke: "currentColor",
49
+ strokeWidth: "2",
50
+ strokeLinecap: "round",
51
+ strokeLinejoin: "round",
52
+ children: /*#__PURE__*/ jsxRuntime.jsx("path", {
53
+ d: "M2 6.5 5 9.5 10 3"
54
+ })
55
+ });
56
+ }
57
+
58
+ exports.MultiStateGlyph = MultiStateGlyph;
59
+ //# sourceMappingURL=MultiStateGlyph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MultiStateGlyph.js","sources":["../../../form/MultiStateGlyph.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { SceneIcon } from '@cratis/scene.react';\nimport { MultiStateOption } from './MultiStateOption';\n\nexport interface MultiStateGlyphProps {\n /** The state being shown. */\n state: MultiStateOption | undefined;\n\n /** Whether the state is the empty (`null`) state, drawn as an empty box. */\n isEmpty: boolean;\n\n /** Whether the control is disabled or read only. */\n isInactive: boolean;\n}\n\n/**\n * The box a multi-state checkbox draws, themed with the PrimeReact checkbox tokens (`--p-checkbox-*`), so\n * it follows the active Scene theme and looks like its sibling `checkbox`. It holds the state's icon - a\n * PrimeIcons class or a qualified icon reference - or a check mark when the state has no icon of its own.\n * An empty state draws only its own icon, if it has one. It is decorative: the state is announced through the control's text, not through this glyph.\n */\nexport function MultiStateGlyph({ state, isEmpty, isInactive }: MultiStateGlyphProps) {\n const icon = state?.icon;\n return (\n <span\n aria-hidden='true'\n data-scene-part='glyph'\n style={{\n display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, boxSizing: 'border-box',\n width: 'var(--p-checkbox-width, 1.125rem)', height: 'var(--p-checkbox-height, 1.125rem)',\n borderRadius: 'var(--p-checkbox-border-radius, 4px)',\n border: `1px solid ${isEmpty ? 'var(--p-checkbox-border-color, currentColor)' : 'var(--p-checkbox-checked-border-color, currentColor)'}`,\n backgroundColor: isEmpty ? 'var(--p-checkbox-background, transparent)' : 'var(--p-checkbox-checked-background, currentColor)',\n color: glyphColor(isEmpty, isInactive),\n fontSize: 'var(--p-checkbox-icon-size, 0.75rem)',\n }}>\n {icon === undefined ? !isEmpty && <CheckMark /> : typeof icon === 'string' ? <i className={icon} /> : <SceneIcon reference={icon} size='var(--p-checkbox-icon-size, 0.75rem)' />}\n </span>\n );\n}\n\nfunction glyphColor(isEmpty: boolean, isInactive: boolean): string {\n if (isInactive) return 'var(--p-checkbox-icon-disabled-color, currentColor)';\n return isEmpty ? 'var(--p-checkbox-icon-color, currentColor)' : 'var(--p-checkbox-icon-checked-color, Canvas)';\n}\n\nfunction CheckMark() {\n return (\n <svg viewBox='0 0 12 12' width='1em' height='1em' fill='none' stroke='currentColor' strokeWidth='2' strokeLinecap='round' strokeLinejoin='round'>\n <path d='M2 6.5 5 9.5 10 3' />\n </svg>\n );\n}\n"],"names":["MultiStateGlyph","state","isEmpty","isInactive","icon","_jsx","span","aria-hidden","data-scene-part","style","display","alignItems","justifyContent","flexShrink","boxSizing","width","height","borderRadius","border","backgroundColor","color","glyphColor","fontSize","undefined","CheckMark","i","className","SceneIcon","reference","size","svg","viewBox","fill","stroke","strokeWidth","strokeLinecap","strokeLinejoin","path","d"],"mappings":";;;;;AAiBA;;;;;IAMO,SAASA,eAAAA,CAAgB,EAAEC,KAAK,EAAEC,OAAO,EAAEC,UAAU,EAAwB,EAAA;AAChF,IAAA,MAAMC,OAAOH,KAAAA,EAAOG,IAAAA;AACpB,IAAA,qBACIC,cAAA,CAACC,MAAAA,EAAAA;QACGC,aAAAA,EAAY,MAAA;QACZC,iBAAAA,EAAgB,OAAA;QAChBC,KAAAA,EAAO;YACHC,OAAAA,EAAS,aAAA;YAAeC,UAAAA,EAAY,QAAA;YAAUC,cAAAA,EAAgB,QAAA;YAAUC,UAAAA,EAAY,CAAA;YAAGC,SAAAA,EAAW,YAAA;YAClGC,KAAAA,EAAO,mCAAA;YAAqCC,MAAAA,EAAQ,oCAAA;YACpDC,YAAAA,EAAc,sCAAA;AACdC,YAAAA,MAAAA,EAAQ,CAAC,UAAU,EAAEhB,OAAAA,GAAU,iDAAiD,sDAAA,CAAA,CAAwD;AACxIiB,YAAAA,eAAAA,EAAiBjB,UAAU,2CAAA,GAA8C,oDAAA;AACzEkB,YAAAA,KAAAA,EAAOC,WAAWnB,OAAAA,EAASC,UAAAA,CAAAA;YAC3BmB,QAAAA,EAAU;AACd,SAAA;kBACClB,IAAAA,KAASmB,SAAAA,GAAY,CAACrB,OAAAA,kBAAWG,cAAA,CAACmB,iBAAe,OAAOpB,IAAAA,KAAS,yBAAWC,cAAA,CAACoB,GAAAA,EAAAA;YAAEC,SAAAA,EAAWtB;2BAAWC,cAAA,CAACsB,qBAAAA,EAAAA;YAAUC,SAAAA,EAAWxB,IAAAA;YAAMyB,IAAAA,EAAK;;;AAGnJ;AAEA,SAASR,UAAAA,CAAWnB,OAAgB,EAAEC,UAAmB,EAAA;AACrD,IAAA,IAAIA,YAAY,OAAO,qDAAA;AACvB,IAAA,OAAOD,UAAU,4CAAA,GAA+C,8CAAA;AACpE;AAEA,SAASsB,SAAAA,GAAAA;AACL,IAAA,qBACInB,cAAA,CAACyB,KAAAA,EAAAA;QAAIC,OAAAA,EAAQ,WAAA;QAAYhB,KAAAA,EAAM,KAAA;QAAMC,MAAAA,EAAO,KAAA;QAAMgB,IAAAA,EAAK,MAAA;QAAOC,MAAAA,EAAO,cAAA;QAAeC,WAAAA,EAAY,GAAA;QAAIC,aAAAA,EAAc,OAAA;QAAQC,cAAAA,EAAe,OAAA;AACrI,QAAA,QAAA,gBAAA/B,cAAA,CAACgC,MAAAA,EAAAA;YAAKC,CAAAA,EAAE;;;AAGpB;;"}
@@ -0,0 +1,123 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var react = require('react');
5
+ var scene_model = require('@cratis/scene.model');
6
+ var properties = require('../properties.js');
7
+ var MultiStateGlyph = require('./MultiStateGlyph.js');
8
+ var multiStateOptions = require('./multiStateOptions.js');
9
+ var multiStateStates = require('./multiStateStates.js');
10
+ var useMultiStateSelection = require('./useMultiStateSelection.js');
11
+
12
+ const visuallyHidden = {
13
+ position: 'absolute',
14
+ width: 1,
15
+ height: 1,
16
+ margin: -1,
17
+ padding: 0,
18
+ overflow: 'hidden',
19
+ clip: 'rect(0 0 0 0)',
20
+ whiteSpace: 'nowrap',
21
+ border: 0
22
+ };
23
+ /**
24
+ * The `PrimeReact:multiStateCheckbox` component.
25
+ *
26
+ * PrimeReact 11 removed MultiStateCheckbox, so Scene renders its original behavior with a native button.
27
+ * It cycles through the authored states in order, including the optional empty (`null`) state, and keeps
28
+ * option values and icons exactly as the element carries them. Each click moves one step; the position is
29
+ * an index, so duplicated or `null` option values do not make later states unreachable.
30
+ *
31
+ * Accessibility: a state cycle is not a true/false choice, so the control does not claim `checkbox`
32
+ * semantics (every non-empty state would announce as "checked"). It is a button whose name is the authored
33
+ * `ariaLabel`, whose description is the current state, and whose state changes are announced through a
34
+ * polite live region. `readOnly` keeps the control focusable and unchanged; `disabled` removes it from the
35
+ * tab order.
36
+ *
37
+ * The control follows the document: a changed `value` or `options` restarts the cycle from the new value,
38
+ * so an inspector edit is reflected immediately. It does not report its own selection to behaviors -
39
+ * Scene's interaction handlers carry no value.
40
+ */ function PrimeMultiStateCheckbox({ element, interactions }) {
41
+ const stateId = react.useId();
42
+ const allowEmpty = properties.booleanProperty(element, 'empty', true);
43
+ const emptyLabel = properties.stringProperty(element, 'emptyLabel', 'No selection');
44
+ const emptyIcon = element.properties.emptyIcon;
45
+ const states = multiStateStates.multiStateStates(multiStateOptions.multiStateOptions(element, emptyLabel), allowEmpty, emptyLabel, typeof emptyIcon === 'string' || scene_model.isIconReference(emptyIcon) ? emptyIcon : undefined);
46
+ const authored = element.properties.value;
47
+ const { index, advance } = useMultiStateSelection.useMultiStateSelection(states, authored === undefined && allowEmpty ? null : authored);
48
+ const [focused, setFocused] = react.useState(false);
49
+ const selected = states[index];
50
+ const readOnly = properties.booleanProperty(element, 'readOnly', false);
51
+ const disabled = !element.isEnabled || properties.booleanProperty(element, 'disabled', false) || states.length === 0;
52
+ const ariaLabel = properties.stringProperty(element, 'ariaLabel', element.name || 'Multi-state checkbox');
53
+ const stateText = selected?.label ?? properties.stringProperty(element, 'placeholder', unmatchedText(states.length, authored, emptyLabel));
54
+ return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
55
+ children: [
56
+ /*#__PURE__*/ jsxRuntime.jsxs("button", {
57
+ type: "button",
58
+ "data-scene-id": element.id,
59
+ "data-scene-component": "multiStateCheckbox",
60
+ "data-scene-state-index": index,
61
+ "aria-label": ariaLabel,
62
+ "aria-describedby": stateId,
63
+ "aria-disabled": readOnly ? true : undefined,
64
+ disabled: disabled,
65
+ style: {
66
+ display: 'inline-flex',
67
+ alignItems: 'center',
68
+ gap: '0.5rem',
69
+ padding: 0,
70
+ border: 0,
71
+ background: 'none',
72
+ font: 'inherit',
73
+ color: 'inherit',
74
+ cursor: disabled ? 'not-allowed' : readOnly ? 'default' : 'pointer',
75
+ opacity: disabled ? 0.6 : 1,
76
+ outline: focused ? 'var(--p-focus-ring-width, 2px) var(--p-focus-ring-style, solid) var(--p-focus-ring-color, currentColor)' : 'none',
77
+ outlineOffset: 'var(--p-focus-ring-offset, 2px)'
78
+ },
79
+ onFocus: (event)=>setFocused(isFocusVisible(event.currentTarget)),
80
+ onBlur: ()=>setFocused(false),
81
+ onClick: (event)=>{
82
+ if (!readOnly) advance();
83
+ interactions?.onClick?.(event);
84
+ if (readOnly) return;
85
+ interactions?.onChange?.();
86
+ interactions?.onSelect?.();
87
+ },
88
+ onDoubleClick: interactions?.onDoubleClick,
89
+ children: [
90
+ /*#__PURE__*/ jsxRuntime.jsx(MultiStateGlyph.MultiStateGlyph, {
91
+ state: selected,
92
+ isEmpty: selected === undefined || selected.value === null,
93
+ isInactive: disabled || readOnly
94
+ }),
95
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
96
+ "aria-hidden": "true",
97
+ children: stateText
98
+ })
99
+ ]
100
+ }),
101
+ /*#__PURE__*/ jsxRuntime.jsx("span", {
102
+ id: stateId,
103
+ role: "status",
104
+ style: visuallyHidden,
105
+ children: stateText
106
+ })
107
+ ]
108
+ });
109
+ }
110
+ function unmatchedText(stateCount, authored, emptyLabel) {
111
+ if (stateCount === 0) return 'No states';
112
+ return authored === undefined ? emptyLabel : 'No matching state';
113
+ }
114
+ function isFocusVisible(target) {
115
+ try {
116
+ return target.matches(':focus-visible');
117
+ } catch {
118
+ return true;
119
+ }
120
+ }
121
+
122
+ exports.PrimeMultiStateCheckbox = PrimeMultiStateCheckbox;
123
+ //# sourceMappingURL=PrimeMultiStateCheckbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PrimeMultiStateCheckbox.js","sources":["../../../form/PrimeMultiStateCheckbox.tsx"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { CSSProperties, useId, useState } from 'react';\nimport { isIconReference } from '@cratis/scene.model';\nimport { RegisteredComponentProps } from '@cratis/scene.react';\nimport { booleanProperty, stringProperty } from '../properties';\nimport { MultiStateGlyph } from './MultiStateGlyph';\nimport { multiStateOptions } from './multiStateOptions';\nimport { multiStateStates } from './multiStateStates';\nimport { useMultiStateSelection } from './useMultiStateSelection';\n\nconst visuallyHidden: CSSProperties = {\n position: 'absolute', width: 1, height: 1, margin: -1, padding: 0, overflow: 'hidden', clip: 'rect(0 0 0 0)', whiteSpace: 'nowrap', border: 0,\n};\n\n/**\n * The `PrimeReact:multiStateCheckbox` component.\n *\n * PrimeReact 11 removed MultiStateCheckbox, so Scene renders its original behavior with a native button.\n * It cycles through the authored states in order, including the optional empty (`null`) state, and keeps\n * option values and icons exactly as the element carries them. Each click moves one step; the position is\n * an index, so duplicated or `null` option values do not make later states unreachable.\n *\n * Accessibility: a state cycle is not a true/false choice, so the control does not claim `checkbox`\n * semantics (every non-empty state would announce as \"checked\"). It is a button whose name is the authored\n * `ariaLabel`, whose description is the current state, and whose state changes are announced through a\n * polite live region. `readOnly` keeps the control focusable and unchanged; `disabled` removes it from the\n * tab order.\n *\n * The control follows the document: a changed `value` or `options` restarts the cycle from the new value,\n * so an inspector edit is reflected immediately. It does not report its own selection to behaviors -\n * Scene's interaction handlers carry no value.\n */\nexport function PrimeMultiStateCheckbox({ element, interactions }: RegisteredComponentProps) {\n const stateId = useId();\n const allowEmpty = booleanProperty(element, 'empty', true);\n const emptyLabel = stringProperty(element, 'emptyLabel', 'No selection');\n const emptyIcon = element.properties.emptyIcon;\n const states = multiStateStates(\n multiStateOptions(element, emptyLabel),\n allowEmpty,\n emptyLabel,\n typeof emptyIcon === 'string' || isIconReference(emptyIcon) ? emptyIcon : undefined);\n const authored = element.properties.value;\n const { index, advance } = useMultiStateSelection(states, authored === undefined && allowEmpty ? null : authored);\n const [focused, setFocused] = useState(false);\n\n const selected = states[index];\n const readOnly = booleanProperty(element, 'readOnly', false);\n const disabled = !element.isEnabled || booleanProperty(element, 'disabled', false) || states.length === 0;\n const ariaLabel = stringProperty(element, 'ariaLabel', element.name || 'Multi-state checkbox');\n const stateText = selected?.label ?? stringProperty(element, 'placeholder', unmatchedText(states.length, authored, emptyLabel));\n\n return (\n <>\n <button\n type='button'\n data-scene-id={element.id}\n data-scene-component='multiStateCheckbox'\n data-scene-state-index={index}\n aria-label={ariaLabel}\n aria-describedby={stateId}\n aria-disabled={readOnly ? true : undefined}\n disabled={disabled}\n style={{\n display: 'inline-flex', alignItems: 'center', gap: '0.5rem', padding: 0, border: 0, background: 'none', font: 'inherit',\n color: 'inherit', cursor: disabled ? 'not-allowed' : readOnly ? 'default' : 'pointer', opacity: disabled ? 0.6 : 1,\n outline: focused ? 'var(--p-focus-ring-width, 2px) var(--p-focus-ring-style, solid) var(--p-focus-ring-color, currentColor)' : 'none',\n outlineOffset: 'var(--p-focus-ring-offset, 2px)',\n }}\n onFocus={(event) => setFocused(isFocusVisible(event.currentTarget))}\n onBlur={() => setFocused(false)}\n onClick={(event) => {\n if (!readOnly) advance();\n interactions?.onClick?.(event);\n if (readOnly) return;\n interactions?.onChange?.();\n interactions?.onSelect?.();\n }}\n onDoubleClick={interactions?.onDoubleClick}>\n <MultiStateGlyph state={selected} isEmpty={selected === undefined || selected.value === null} isInactive={disabled || readOnly} />\n <span aria-hidden='true'>{stateText}</span>\n </button>\n <span id={stateId} role='status' style={visuallyHidden}>{stateText}</span>\n </>\n );\n}\n\nfunction unmatchedText(stateCount: number, authored: unknown, emptyLabel: string): string {\n if (stateCount === 0) return 'No states';\n return authored === undefined ? emptyLabel : 'No matching state';\n}\n\nfunction isFocusVisible(target: HTMLElement): boolean {\n try {\n return target.matches(':focus-visible');\n } catch {\n return true;\n }\n}\n"],"names":["visuallyHidden","position","width","height","margin","padding","overflow","clip","whiteSpace","border","PrimeMultiStateCheckbox","element","interactions","stateId","useId","allowEmpty","booleanProperty","emptyLabel","stringProperty","emptyIcon","properties","states","multiStateStates","multiStateOptions","isIconReference","undefined","authored","value","index","advance","useMultiStateSelection","focused","setFocused","useState","selected","readOnly","disabled","isEnabled","length","ariaLabel","name","stateText","label","unmatchedText","_jsxs","_Fragment","button","type","data-scene-id","id","data-scene-component","data-scene-state-index","aria-label","aria-describedby","aria-disabled","style","display","alignItems","gap","background","font","color","cursor","opacity","outline","outlineOffset","onFocus","event","isFocusVisible","currentTarget","onBlur","onClick","onChange","onSelect","onDoubleClick","_jsx","MultiStateGlyph","state","isEmpty","isInactive","span","aria-hidden","role","stateCount","target","matches"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ 'use strict';
2
+
3
+ var scene_model = require('@cratis/scene.model');
4
+ var properties = require('../properties.js');
5
+
6
+ // Copyright (c) Cratis. All rights reserved.
7
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8
+ /**
9
+ * Reads multi-state options without reshaping their values, dropping any of them, or changing their order.
10
+ *
11
+ * This follows the original PrimeReact control. An option that is a record gives its value through
12
+ * `optionValue` (default, and when that field is absent: its `value` field, and the whole option when it has none) and its label through
13
+ * `optionLabel` (default: its `label` field). Any other option - a string, number, boolean, `null` or an
14
+ * array - is its own value. A label that is not text is shown as its JSON, so a numeric or boolean label,
15
+ * or an option with no label at all, still produces a state the user can reach. A `null` value with no
16
+ * label of its own is labeled with `emptyLabel`.
17
+ *
18
+ * A state's icon is, in order: the option's own `icon`, then the entry of the element's `icons` that is
19
+ * aligned with the option (an array) or keyed by its value (an object). Either may be a PrimeIcons class
20
+ * name, kept for legacy documents, or a qualified {@link IconReference}.
21
+ */ function multiStateOptions(element, emptyLabel) {
22
+ const labelPath = properties.stringProperty(element, 'optionLabel');
23
+ const valuePath = properties.stringProperty(element, 'optionValue');
24
+ const icons = element.properties.icons;
25
+ return properties.arrayProperty(element, 'options').map((option, index)=>{
26
+ const record = isRecord(option) ? option : undefined;
27
+ const value = record === undefined ? option : valueOf(record, valuePath);
28
+ const label = record === undefined ? undefined : resolvePath(record, labelPath ?? 'label');
29
+ const icon = toIcon(record?.icon) ?? iconAt(icons, value, index);
30
+ return {
31
+ label: labelText(label, value, emptyLabel),
32
+ value,
33
+ ...icon === undefined ? {} : {
34
+ icon
35
+ }
36
+ };
37
+ });
38
+ }
39
+ function valueOf(record, valuePath) {
40
+ const authored = valuePath === undefined ? undefined : resolvePath(record, valuePath);
41
+ if (authored !== undefined) return authored;
42
+ return record.value !== undefined ? record.value : record;
43
+ }
44
+ function resolvePath(record, path) {
45
+ if (Object.hasOwn(record, path)) return record[path];
46
+ let current = record;
47
+ for (const segment of path.split('.')){
48
+ if (!isRecord(current) || !Object.hasOwn(current, segment)) return undefined;
49
+ current = current[segment];
50
+ }
51
+ return current;
52
+ }
53
+ function labelText(label, value, emptyLabel) {
54
+ if (typeof label === 'string' && label.length > 0) return label;
55
+ if (label !== undefined && label !== null && label !== '') return display(label);
56
+ return value === null ? emptyLabel : display(value);
57
+ }
58
+ function display(value) {
59
+ const text = typeof value === 'string' ? value : JSON.stringify(value) ?? String(value);
60
+ return text === '' ? '""' : text;
61
+ }
62
+ function toIcon(candidate) {
63
+ if (typeof candidate === 'string' && candidate.length > 0) return candidate;
64
+ return scene_model.isIconReference(candidate) ? candidate : undefined;
65
+ }
66
+ function iconAt(icons, value, index) {
67
+ if (Array.isArray(icons)) return toIcon(icons[index]);
68
+ if (!isRecord(icons)) return undefined;
69
+ const isKey = value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';
70
+ return isKey ? toIcon(icons[String(value)]) : undefined;
71
+ }
72
+ function isRecord(value) {
73
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
74
+ }
75
+
76
+ exports.multiStateOptions = multiStateOptions;
77
+ //# sourceMappingURL=multiStateOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiStateOptions.js","sources":["../../../form/multiStateOptions.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { SceneElement, isIconReference } from '@cratis/scene.model';\nimport { arrayProperty, stringProperty } from '../properties';\nimport { MultiStateOption } from './MultiStateOption';\n\n/**\n * Reads multi-state options without reshaping their values, dropping any of them, or changing their order.\n *\n * This follows the original PrimeReact control. An option that is a record gives its value through\n * `optionValue` (default, and when that field is absent: its `value` field, and the whole option when it has none) and its label through\n * `optionLabel` (default: its `label` field). Any other option - a string, number, boolean, `null` or an\n * array - is its own value. A label that is not text is shown as its JSON, so a numeric or boolean label,\n * or an option with no label at all, still produces a state the user can reach. A `null` value with no\n * label of its own is labeled with `emptyLabel`.\n *\n * A state's icon is, in order: the option's own `icon`, then the entry of the element's `icons` that is\n * aligned with the option (an array) or keyed by its value (an object). Either may be a PrimeIcons class\n * name, kept for legacy documents, or a qualified {@link IconReference}.\n */\nexport function multiStateOptions(element: SceneElement, emptyLabel: string): MultiStateOption[] {\n const labelPath = stringProperty(element, 'optionLabel');\n const valuePath = stringProperty(element, 'optionValue');\n const icons = element.properties.icons;\n\n return arrayProperty(element, 'options').map((option, index) => {\n const record = isRecord(option) ? option : undefined;\n const value = record === undefined ? option : valueOf(record, valuePath);\n const label = record === undefined ? undefined : resolvePath(record, labelPath ?? 'label');\n const icon = toIcon(record?.icon) ?? iconAt(icons, value, index);\n return { label: labelText(label, value, emptyLabel), value, ...(icon === undefined ? {} : { icon }) };\n });\n}\n\nfunction valueOf(record: Record<string, unknown>, valuePath: string | undefined): unknown {\n const authored = valuePath === undefined ? undefined : resolvePath(record, valuePath);\n if (authored !== undefined) return authored;\n return record.value !== undefined ? record.value : record;\n}\n\nfunction resolvePath(record: Record<string, unknown>, path: string): unknown {\n if (Object.hasOwn(record, path)) return record[path];\n let current: unknown = record;\n for (const segment of path.split('.')) {\n if (!isRecord(current) || !Object.hasOwn(current, segment)) return undefined;\n current = current[segment];\n }\n return current;\n}\n\nfunction labelText(label: unknown, value: unknown, emptyLabel: string): string {\n if (typeof label === 'string' && label.length > 0) return label;\n if (label !== undefined && label !== null && label !== '') return display(label);\n return value === null ? emptyLabel : display(value);\n}\n\nfunction display(value: unknown): string {\n const text = typeof value === 'string' ? value : JSON.stringify(value) ?? String(value);\n return text === '' ? '\"\"' : text;\n}\n\nfunction toIcon(candidate: unknown): MultiStateOption['icon'] {\n if (typeof candidate === 'string' && candidate.length > 0) return candidate;\n return isIconReference(candidate) ? candidate : undefined;\n}\n\nfunction iconAt(icons: unknown, value: unknown, index: number): MultiStateOption['icon'] {\n if (Array.isArray(icons)) return toIcon(icons[index]);\n if (!isRecord(icons)) return undefined;\n\n const isKey = value === null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean';\n return isKey ? toIcon(icons[String(value)]) : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n"],"names":["multiStateOptions","element","emptyLabel","labelPath","stringProperty","valuePath","icons","properties","arrayProperty","map","option","index","record","isRecord","undefined","value","valueOf","label","resolvePath","icon","toIcon","iconAt","labelText","authored","path","Object","hasOwn","current","segment","split","length","display","text","JSON","stringify","String","candidate","isIconReference","Array","isArray","isKey"],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ // Copyright (c) Cratis. All rights reserved.
4
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5
+ /**
6
+ * Builds the ordered states a multi-state checkbox cycles through.
7
+ *
8
+ * With the empty state allowed, a state whose value is `null` comes first - unless an authored option
9
+ * already has the value `null`, in which case that option *is* the empty state and keeps its authored
10
+ * position, label and icon. Adding a second `null` state would leave two states with one value, and a
11
+ * control that finds its place by value could then never move past the first of them.
12
+ *
13
+ * @param options The authored options, in order.
14
+ * @param allowEmpty Whether a `null` state is available.
15
+ * @param emptyLabel The label of the synthesized empty state.
16
+ * @param emptyIcon The icon of the synthesized empty state.
17
+ */ function multiStateStates(options, allowEmpty, emptyLabel, emptyIcon) {
18
+ if (!allowEmpty || options.some((option)=>option.value === null)) return options;
19
+ return [
20
+ {
21
+ label: emptyLabel,
22
+ value: null,
23
+ ...emptyIcon === undefined ? {} : {
24
+ icon: emptyIcon
25
+ }
26
+ },
27
+ ...options
28
+ ];
29
+ }
30
+
31
+ exports.multiStateStates = multiStateStates;
32
+ //# sourceMappingURL=multiStateStates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiStateStates.js","sources":["../../../form/multiStateStates.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { IconReference } from '@cratis/scene.model';\nimport { MultiStateOption } from './MultiStateOption';\n\n/**\n * Builds the ordered states a multi-state checkbox cycles through.\n *\n * With the empty state allowed, a state whose value is `null` comes first - unless an authored option\n * already has the value `null`, in which case that option *is* the empty state and keeps its authored\n * position, label and icon. Adding a second `null` state would leave two states with one value, and a\n * control that finds its place by value could then never move past the first of them.\n *\n * @param options The authored options, in order.\n * @param allowEmpty Whether a `null` state is available.\n * @param emptyLabel The label of the synthesized empty state.\n * @param emptyIcon The icon of the synthesized empty state.\n */\nexport function multiStateStates(options: MultiStateOption[], allowEmpty: boolean, emptyLabel: string, emptyIcon: string | IconReference | undefined): MultiStateOption[] {\n if (!allowEmpty || options.some(option => option.value === null)) return options;\n return [{ label: emptyLabel, value: null, ...(emptyIcon === undefined ? {} : { icon: emptyIcon }) }, ...options];\n}\n"],"names":["multiStateStates","options","allowEmpty","emptyLabel","emptyIcon","some","option","value","label","undefined","icon"],"mappings":";;AAAA;AACA;AAKA;;;;;;;;;;;;IAaO,SAASA,gBAAAA,CAAiBC,OAA2B,EAAEC,UAAmB,EAAEC,UAAkB,EAAEC,SAA6C,EAAA;IAChJ,IAAI,CAACF,UAAAA,IAAcD,OAAAA,CAAQI,IAAI,CAACC,CAAAA,MAAAA,GAAUA,MAAAA,CAAOC,KAAK,KAAK,IAAA,CAAA,EAAO,OAAON,OAAAA;IACzE,OAAO;AAAC,QAAA;YAAEO,KAAAA,EAAOL,UAAAA;YAAYI,KAAAA,EAAO,IAAA;YAAM,GAAIH,SAAAA,KAAcK,SAAAA,GAAY,EAAC,GAAI;gBAAEC,IAAAA,EAAMN;;AAAa,SAAA;AAAMH,QAAAA,GAAAA;AAAQ,KAAA;AACpH;;"}
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var structurallyEqual = require('../structurallyEqual.js');
5
+
6
+ // Copyright (c) Cratis. All rights reserved.
7
+ // Licensed under the MIT license. See LICENSE file in the project root for full license information.
8
+ /**
9
+ * The state a multi-state checkbox is in, as an index into its states.
10
+ *
11
+ * The position is tracked by index, not recovered by looking the current value up: several states can
12
+ * share a value (a duplicated option), and a lookup by value always finds the first of them, which would
13
+ * make every later state unreachable. The index follows the cycle; the value is only used to find the
14
+ * starting position.
15
+ *
16
+ * The control is driven by the document as well as by the user. When the authored `value` or the states
17
+ * change in content - an edit in the inspector, a hydrated document - the selection starts again from the
18
+ * new value. A document clone with equal content changes nothing, so the user's position survives it.
19
+ *
20
+ * @param states The states, in cycle order.
21
+ * @param value The authored current value.
22
+ * @returns The selected index (`-1` when the value matches no state) and a function that moves to the next.
23
+ */ function useMultiStateSelection(states, value) {
24
+ const values = states.map((state)=>state.value);
25
+ const start = ()=>({
26
+ source: value,
27
+ values,
28
+ index: values.findIndex((candidate)=>structurallyEqual.structurallyEqual(candidate, value))
29
+ });
30
+ const [selection, setSelection] = react.useState(start);
31
+ let current = selection;
32
+ if (!structurallyEqual.structurallyEqual(selection.source, value) || !structurallyEqual.structurallyEqual(selection.values, values)) {
33
+ current = start();
34
+ setSelection(current);
35
+ }
36
+ const advance = ()=>{
37
+ const index = states.length === 0 ? -1 : (current.index + 1) % states.length;
38
+ setSelection({
39
+ ...current,
40
+ index
41
+ });
42
+ return index;
43
+ };
44
+ return {
45
+ index: current.index,
46
+ advance
47
+ };
48
+ }
49
+
50
+ exports.useMultiStateSelection = useMultiStateSelection;
51
+ //# sourceMappingURL=useMultiStateSelection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMultiStateSelection.js","sources":["../../../form/useMultiStateSelection.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useState } from 'react';\nimport { structurallyEqual } from '../structurallyEqual';\nimport { MultiStateOption } from './MultiStateOption';\n\ninterface Selection {\n source: unknown;\n values: unknown[];\n index: number;\n}\n\n/**\n * The state a multi-state checkbox is in, as an index into its states.\n *\n * The position is tracked by index, not recovered by looking the current value up: several states can\n * share a value (a duplicated option), and a lookup by value always finds the first of them, which would\n * make every later state unreachable. The index follows the cycle; the value is only used to find the\n * starting position.\n *\n * The control is driven by the document as well as by the user. When the authored `value` or the states\n * change in content - an edit in the inspector, a hydrated document - the selection starts again from the\n * new value. A document clone with equal content changes nothing, so the user's position survives it.\n *\n * @param states The states, in cycle order.\n * @param value The authored current value.\n * @returns The selected index (`-1` when the value matches no state) and a function that moves to the next.\n */\nexport function useMultiStateSelection(states: MultiStateOption[], value: unknown): { index: number; advance(): number } {\n const values = states.map(state => state.value);\n const start = (): Selection => ({ source: value, values, index: values.findIndex(candidate => structurallyEqual(candidate, value)) });\n const [selection, setSelection] = useState<Selection>(start);\n\n let current = selection;\n if (!structurallyEqual(selection.source, value) || !structurallyEqual(selection.values, values)) {\n current = start();\n setSelection(current);\n }\n\n const advance = () => {\n const index = states.length === 0 ? -1 : (current.index + 1) % states.length;\n setSelection({ ...current, index });\n return index;\n };\n\n return { index: current.index, advance };\n}\n"],"names":["useMultiStateSelection","states","value","values","map","state","start","source","index","findIndex","candidate","structurallyEqual","selection","setSelection","useState","current","advance","length"],"mappings":";;;;;AAAA;AACA;AAYA;;;;;;;;;;;;;;;AAeC,IACM,SAASA,sBAAAA,CAAuBC,MAA0B,EAAEC,KAAc,EAAA;AAC7E,IAAA,MAAMC,SAASF,MAAAA,CAAOG,GAAG,CAACC,CAAAA,KAAAA,GAASA,MAAMH,KAAK,CAAA;IAC9C,MAAMI,KAAAA,GAAQ,KAAkB;YAAEC,MAAAA,EAAQL,KAAAA;AAAOC,YAAAA,MAAAA;AAAQK,YAAAA,KAAAA,EAAOL,OAAOM,SAAS,CAACC,CAAAA,SAAAA,GAAaC,oCAAkBD,SAAAA,EAAWR,KAAAA,CAAAA;SAAQ,CAAA;AACnI,IAAA,MAAM,CAACU,SAAAA,EAAWC,YAAAA,CAAa,GAAGC,cAAAA,CAAoBR,KAAAA,CAAAA;AAEtD,IAAA,IAAIS,OAAAA,GAAUH,SAAAA;IACd,IAAI,CAACD,mCAAAA,CAAkBC,SAAAA,CAAUL,MAAM,EAAEL,KAAAA,CAAAA,IAAU,CAACS,mCAAAA,CAAkBC,SAAAA,CAAUT,MAAM,EAAEA,MAAAA,CAAAA,EAAS;QAC7FY,OAAAA,GAAUT,KAAAA,EAAAA;QACVO,YAAAA,CAAaE,OAAAA,CAAAA;AACjB,IAAA;AAEA,IAAA,MAAMC,OAAAA,GAAU,IAAA;AACZ,QAAA,MAAMR,KAAAA,GAAQP,MAAAA,CAAOgB,MAAM,KAAK,IAAI,EAAC,GAAI,CAACF,QAAQP,KAAK,GAAG,CAAA,IAAKP,OAAOgB,MAAM;QAC5EJ,YAAAA,CAAa;AAAE,YAAA,GAAGE,OAAO;AAAEP,YAAAA;AAAM,SAAA,CAAA;QACjC,OAAOA,KAAAA;AACX,IAAA,CAAA;IAEA,OAAO;AAAEA,QAAAA,KAAAA,EAAOO,QAAQP,KAAK;AAAEQ,QAAAA;AAAQ,KAAA;AAC3C;;"}