@arcanewizards/timecode-toolbox 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,11 +14,11 @@ generate and convert timecode signals of different types.
14
14
  </h2>
15
15
 
16
16
  <p align="center">
17
- <a href="https://arcanewizards.com/download/timecode-toolbox/latest/macos-arm64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/macos-arm64/button" height="50" alt="Download MacOS (Apple Silicon / ARM) Desktop App"/></a>
17
+ <a href="https://arcanewizards.com/download/timecode-toolbox/latest/macos-arm64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/macos-arm64/button?cb=1" height="50" alt="Download MacOS (Apple Silicon / ARM) Desktop App"/></a>
18
18
  &nbsp;&nbsp;
19
- <a href="https://arcanewizards.com/download/timecode-toolbox/latest/macos-x64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/macos-x64/button" height="50" alt="Download MacOS (Intel / x64) Desktop App"/></a>
19
+ <a href="https://arcanewizards.com/download/timecode-toolbox/latest/macos-x64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/macos-x64/button?cb=1" height="50" alt="Download MacOS (Intel / x64) Desktop App"/></a>
20
20
  &nbsp;&nbsp;
21
- <a href="https://arcanewizards.com/download/timecode-toolbox/latest/windows-x64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/windows-x64/button" height="50" alt="Download Windows (x64) Desktop App"/></a>
21
+ <a href="https://arcanewizards.com/download/timecode-toolbox/latest/windows-x64"><img src="https://arcanewizards.com/download/timecode-toolbox/latest/windows-x64/button?cb=1" height="50" alt="Download Windows (x64) Desktop App"/></a>
22
22
  </p>
23
23
 
24
24
  ## Headless / CLI Version
@@ -15989,6 +15989,10 @@ var STRINGS = {
15989
15989
  },
15990
15990
  inputs: {
15991
15991
  title: "INPUTS",
15992
+ unnamed: "Unnamed Input",
15993
+ enable: "Enable Input",
15994
+ disable: "Disable Input",
15995
+ edit: "Edit Input",
15992
15996
  noChildren: "No inputs yet. Please add one using the buttons below.",
15993
15997
  addButton: (protocol) => `Add ${protocol}`,
15994
15998
  addDialog: (protocol) => `Add ${protocol} Input`,
@@ -16012,6 +16016,8 @@ var STRINGS = {
16012
16016
  delay: (delayMs) => `Delay: ${MS_FORMAT.format(delayMs)}`,
16013
16017
  generators: {
16014
16018
  title: "GENERATORS",
16019
+ unnamed: "Unnamed Generator",
16020
+ edit: "Edit Generator",
16015
16021
  noChildren: "No generators yet. Please add one using the buttons below.",
16016
16022
  type: {
16017
16023
  clock: "Clock"
@@ -16023,6 +16029,11 @@ var STRINGS = {
16023
16029
  },
16024
16030
  outputs: {
16025
16031
  title: "OUTPUTS",
16032
+ unnamed: "Unnamed Output",
16033
+ enable: "Enable Output",
16034
+ disable: "Disable Output",
16035
+ link: "Link Output",
16036
+ edit: "Edit Output",
16026
16037
  noChildren: "No outputs yet. Please add one using the buttons below.",
16027
16038
  addButton: (protocol) => `Add ${protocol}`,
16028
16039
  addDialog: (protocol) => `Add ${protocol} Output`,
@@ -16355,7 +16366,9 @@ var TimecodeDisplay = ({
16355
16366
  id,
16356
16367
  timecode: { state, metadata },
16357
16368
  config,
16358
- headerComponents
16369
+ headerComponents,
16370
+ disabled,
16371
+ rootState
16359
16372
  }) => {
16360
16373
  const { handlers, callHandler } = useApplicationHandlers();
16361
16374
  const hooks = id && getTreeValue(handlers, id);
@@ -16406,29 +16419,41 @@ var TimecodeDisplay = ({
16406
16419
  )
16407
16420
  ),
16408
16421
  children: [
16409
- headerComponents && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex flex-wrap gap-0.25", children: headerComponents }),
16422
+ headerComponents && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex gap-0.25", children: headerComponents }),
16410
16423
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16411
16424
  SizeAwareDiv,
16412
16425
  {
16413
- className: cn(
16414
- "relative min-h-timecode-min-height grow",
16415
- cnd(state?.state === "stopped", "opacity-50"),
16416
- cnd(
16417
- hooks?.play && hooks?.pause,
16418
- `
16419
- cursor-pointer
16420
- hover:opacity-100
16421
- `
16422
- )
16423
- ),
16426
+ className: "relative min-h-timecode-min-height grow",
16424
16427
  onClick: toggle,
16425
- children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: cn("font-mono text-timecode-adaptive"), children: state.state === "none" ? "--:--:--:---" : state.state === "stopped" ? displayMillis(state.positionMillis) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16426
- ActiveTimecodeText,
16428
+ children: disabled ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16429
+ SizeAwareDiv,
16427
16430
  {
16428
- effectiveStartTimeMillis: state.effectiveStartTimeMillis,
16429
- speed: state.speed
16431
+ className: "\n pointer-events-none absolute inset-0 flex items-center\n justify-center\n ",
16432
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Icon2, { icon: "pause", className: "text-timecode-adaptive" })
16430
16433
  }
16431
- ) }) })
16434
+ ) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16435
+ "div",
16436
+ {
16437
+ className: cn(
16438
+ "absolute inset-0 flex items-center justify-center",
16439
+ cnd(state?.state === "stopped", "opacity-50"),
16440
+ cnd(
16441
+ hooks?.play && hooks?.pause,
16442
+ `
16443
+ cursor-pointer
16444
+ hover:opacity-100
16445
+ `
16446
+ )
16447
+ ),
16448
+ children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: cn("font-mono text-timecode-adaptive"), children: state.state === "none" ? "--:--:--:---" : state.state === "stopped" ? displayMillis(state.positionMillis) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16449
+ ActiveTimecodeText,
16450
+ {
16451
+ effectiveStartTimeMillis: state.effectiveStartTimeMillis,
16452
+ speed: state.speed
16453
+ }
16454
+ ) })
16455
+ }
16456
+ )
16432
16457
  }
16433
16458
  ),
16434
16459
  hooks?.pause || hooks?.play ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex justify-center gap-px", children: [
@@ -16516,9 +16541,53 @@ var TimecodeDisplay = ({
16516
16541
  metadata.artist && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "grow truncate bg-sigil-bg-light p-0.5", children: metadata.artist })
16517
16542
  ] })
16518
16543
  }
16519
- ) : null
16544
+ ) : null,
16545
+ rootState.errors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex gap-px", children: rootState.errors.map((error, index2) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16546
+ "div",
16547
+ {
16548
+ className: "\n grow truncate bg-sigil-usage-red-background p-0.5\n text-sigil-usage-red-text\n ",
16549
+ children: error
16550
+ },
16551
+ index2
16552
+ )) }),
16553
+ rootState.warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex gap-px", children: rootState.warnings.map((warning, index2) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16554
+ "div",
16555
+ {
16556
+ className: "\n grow truncate bg-sigil-usage-orange-background p-0.5\n text-sigil-usage-orange-text\n ",
16557
+ children: warning
16558
+ },
16559
+ index2
16560
+ )) })
16520
16561
  ] });
16521
16562
  };
16563
+ var getLinkedSourceInfo = (link, config) => {
16564
+ if (!link) {
16565
+ return void 0;
16566
+ }
16567
+ let info = void 0;
16568
+ if (link[0] === "input") {
16569
+ const input = config.inputs?.[link[1]];
16570
+ if (input) {
16571
+ info = {
16572
+ color: input.color,
16573
+ type: STRINGS.protocols[input.definition.type].short,
16574
+ name: input.name ? [input.name] : [],
16575
+ namePlaceholder: STRINGS.inputs.unnamed
16576
+ };
16577
+ }
16578
+ } else if (link[0] === "generator") {
16579
+ const generator = config.generators?.[link[1]];
16580
+ if (generator) {
16581
+ info = {
16582
+ color: generator.color,
16583
+ type: STRINGS.generators.type[generator.definition.type],
16584
+ name: generator.name ? [generator.name] : [],
16585
+ namePlaceholder: STRINGS.generators.unnamed
16586
+ };
16587
+ }
16588
+ }
16589
+ return info;
16590
+ };
16522
16591
  var EMPTY_TIMECODE = {
16523
16592
  name: null,
16524
16593
  state: {
@@ -16537,8 +16606,10 @@ var TimecodeTreeDisplay = ({
16537
16606
  id,
16538
16607
  type,
16539
16608
  name,
16609
+ link,
16540
16610
  color,
16541
16611
  timecode,
16612
+ rootState,
16542
16613
  namePlaceholder,
16543
16614
  buttons,
16544
16615
  assignToOutput
@@ -16552,8 +16623,8 @@ var TimecodeTreeDisplay = ({
16552
16623
  });
16553
16624
  }
16554
16625
  }, [id, openNewWidow]);
16555
- name = timecode?.name ? [...name, timecode.name] : name;
16556
- if (isTimecodeGroup(timecode) && Object.values(timecode.timecodes).length) {
16626
+ name = timecode !== "disabled" && timecode?.name ? [...name, timecode.name] : name;
16627
+ if (timecode !== "disabled" && isTimecodeGroup(timecode) && Object.values(timecode.timecodes).length) {
16557
16628
  return Object.entries(timecode.timecodes).map(([key, child]) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16558
16629
  TimecodeTreeDisplay,
16559
16630
  {
@@ -16563,6 +16634,7 @@ var TimecodeTreeDisplay = ({
16563
16634
  name,
16564
16635
  color: timecode.color ?? color,
16565
16636
  timecode: child,
16637
+ rootState,
16566
16638
  namePlaceholder,
16567
16639
  buttons,
16568
16640
  assignToOutput
@@ -16580,28 +16652,67 @@ var TimecodeTreeDisplay = ({
16580
16652
  TimecodeDisplay,
16581
16653
  {
16582
16654
  id,
16583
- timecode: isTimecodeInstance(timecode) ? timecode : EMPTY_TIMECODE,
16655
+ timecode: timecode !== "disabled" && isTimecodeInstance(timecode) ? timecode : EMPTY_TIMECODE,
16656
+ rootState,
16657
+ disabled: timecode === "disabled",
16584
16658
  config,
16585
16659
  headerComponents: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
16586
- /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex grow items-start gap-0.25", children: [
16587
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16588
- "div",
16589
- {
16590
- className: "\n m-0.25 rounded-md border border-sigil-bg-light\n bg-timecode-usage-foreground px-1 py-0.25 text-sigil-control\n text-timecode-usage-text\n ",
16591
- children: type
16592
- }
16593
- ),
16594
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16660
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { className: "flex grow basis-0 items-start gap-0.25", children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "grow", children: [
16661
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "flex items-center gap-0.25", children: [
16662
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16663
+ "div",
16664
+ {
16665
+ className: "\n m-0.25 rounded-md border border-sigil-bg-light\n bg-timecode-usage-foreground px-1 py-0.25\n text-sigil-control text-timecode-usage-text\n ",
16666
+ children: type
16667
+ }
16668
+ ),
16669
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16670
+ "div",
16671
+ {
16672
+ className: cn(
16673
+ "w-0 grow truncate p-0.5",
16674
+ cnd(name.length, "font-bold", "italic opacity-50")
16675
+ ),
16676
+ children: name.length ? name.join(" / ") : namePlaceholder
16677
+ }
16678
+ )
16679
+ ] }),
16680
+ link && /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
16595
16681
  "div",
16596
16682
  {
16597
- className: cn(
16598
- "grow basis-0 truncate p-0.5",
16599
- cnd(name.length, "font-bold", "italic opacity-50")
16683
+ className: "\n flex items-center gap-0.25 text-timecode-usage-foreground\n ",
16684
+ style: cssSigilColorUsageVariables(
16685
+ "timecode-usage",
16686
+ // Override timecode color with the user hint preferences
16687
+ // when no color is specified
16688
+ // as that will be what's used by the linked input/generator
16689
+ sigilColorUsage(link.color ?? "hint")
16600
16690
  ),
16601
- children: name.length ? name.join(" / ") : namePlaceholder
16691
+ children: [
16692
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
16693
+ "div",
16694
+ {
16695
+ className: "\n m-0.25 flex items-center gap-0.25 rounded-md border\n border-sigil-bg-light bg-timecode-usage-foreground px-1\n py-0.25 text-sigil-control text-timecode-usage-text\n ",
16696
+ children: [
16697
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Icon2, { icon: "link", className: "text-[120%]" }),
16698
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: link.type })
16699
+ ]
16700
+ }
16701
+ ),
16702
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16703
+ "div",
16704
+ {
16705
+ className: cn(
16706
+ "w-0 grow truncate p-0.5",
16707
+ cnd(link.name.length, "font-bold", "italic opacity-50")
16708
+ ),
16709
+ children: link.name.length ? link.name.join(" / ") : link.namePlaceholder
16710
+ }
16711
+ )
16712
+ ]
16602
16713
  }
16603
16714
  )
16604
- ] }),
16715
+ ] }) }),
16605
16716
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(ControlButtonGroup, { className: "rounded-md bg-sigil-bg-light", children: [
16606
16717
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
16607
16718
  ControlButton,
@@ -16639,7 +16750,7 @@ var FullscreenTimecodeDisplay = ({
16639
16750
  return getTimecodeInstance(applicationState, id);
16640
16751
  } else {
16641
16752
  const c = config.outputs[id[1]];
16642
- if (!c) {
16753
+ if (!c || !c.enabled) {
16643
16754
  return null;
16644
16755
  }
16645
16756
  return augmentUpstreamTimecodeWithOutputMetadata(
@@ -16648,6 +16759,15 @@ var FullscreenTimecodeDisplay = ({
16648
16759
  );
16649
16760
  }
16650
16761
  }, [applicationState, id, config.outputs]);
16762
+ const linkedSourceInfo = (0, import_react31.useMemo)(() => {
16763
+ if (isOutputInstanceId(id)) {
16764
+ const c = config.outputs[id[1]];
16765
+ if (c?.link) {
16766
+ return getLinkedSourceInfo(c.link, config);
16767
+ }
16768
+ }
16769
+ return void 0;
16770
+ }, [id, config]);
16651
16771
  const instanceConfig = (0, import_react31.useMemo)(() => {
16652
16772
  if (isInputInstanceId(id)) {
16653
16773
  const c = config.inputs[id[1]];
@@ -16659,7 +16779,8 @@ var FullscreenTimecodeDisplay = ({
16659
16779
  type: STRINGS.protocols[c.definition.type].short,
16660
16780
  name: c.name ? [c.name] : [],
16661
16781
  color: c.color,
16662
- namePlaceholder: `Unnamed Input`
16782
+ namePlaceholder: STRINGS.inputs.unnamed,
16783
+ disabled: !c.enabled
16663
16784
  };
16664
16785
  } else if (isGeneratorInstanceId(id)) {
16665
16786
  const c = config.generators[id[1]];
@@ -16671,7 +16792,8 @@ var FullscreenTimecodeDisplay = ({
16671
16792
  type: STRINGS.generators.type[c.definition.type],
16672
16793
  name: c.name ? [c.name] : [],
16673
16794
  color: c.color,
16674
- namePlaceholder: `Unnamed Generator`
16795
+ namePlaceholder: STRINGS.generators.unnamed,
16796
+ disabled: false
16675
16797
  };
16676
16798
  } else {
16677
16799
  const c = config.outputs[id[1]];
@@ -16683,10 +16805,29 @@ var FullscreenTimecodeDisplay = ({
16683
16805
  type: STRINGS.protocols[c.definition.type].short,
16684
16806
  name: c.name ? [c.name] : [],
16685
16807
  color: c.color,
16686
- namePlaceholder: `Unnamed Output`
16808
+ namePlaceholder: STRINGS.outputs.unnamed,
16809
+ disabled: !c.enabled
16687
16810
  };
16688
16811
  }
16689
16812
  }, [id, config]);
16813
+ const rootState = (0, import_react31.useMemo)(() => {
16814
+ if (isInputInstanceId(id)) {
16815
+ return {
16816
+ errors: applicationState.inputs?.[id[1]]?.errors ?? [],
16817
+ warnings: applicationState.inputs?.[id[1]]?.warnings ?? []
16818
+ };
16819
+ } else if (isGeneratorInstanceId(id)) {
16820
+ return {
16821
+ errors: [],
16822
+ warnings: []
16823
+ };
16824
+ } else {
16825
+ return {
16826
+ errors: applicationState.outputs?.[id[1]]?.errors ?? [],
16827
+ warnings: applicationState.outputs?.[id[1]]?.warnings ?? []
16828
+ };
16829
+ }
16830
+ }, [id, applicationState]);
16690
16831
  if (!instanceConfig) {
16691
16832
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
16692
16833
  SizeAwareDiv,
@@ -16707,9 +16848,11 @@ var FullscreenTimecodeDisplay = ({
16707
16848
  TimecodeTreeDisplay,
16708
16849
  {
16709
16850
  id,
16710
- timecode,
16851
+ timecode: instanceConfig.disabled ? "disabled" : timecode,
16852
+ rootState,
16711
16853
  assignToOutput: null,
16712
16854
  buttons: null,
16855
+ link: linkedSourceInfo,
16713
16856
  ...instanceConfig
16714
16857
  }
16715
16858
  )
@@ -17147,7 +17290,7 @@ var OutputDisplay = ({
17147
17290
  setAssignToOutput
17148
17291
  }) => {
17149
17292
  const applicationState = useApplicationState();
17150
- const { updateConfig } = (0, import_react32.useContext)(ConfigContext);
17293
+ const { config: allConfig, updateConfig } = (0, import_react32.useContext)(ConfigContext);
17151
17294
  const clearLink = (0, import_react32.useCallback)(() => {
17152
17295
  updateConfig((current) => {
17153
17296
  const currentOutput = current.outputs?.[uuid];
@@ -17175,6 +17318,10 @@ var OutputDisplay = ({
17175
17318
  const tc = config.link && getTimecodeInstance(applicationState, config.link);
17176
17319
  return augmentUpstreamTimecodeWithOutputMetadata(tc, config);
17177
17320
  }, [applicationState, config]);
17321
+ const link = (0, import_react32.useMemo)(
17322
+ () => getLinkedSourceInfo(config.link, allConfig),
17323
+ [config.link, allConfig]
17324
+ );
17178
17325
  const toggleEnabled = (0, import_react32.useCallback)(() => {
17179
17326
  updateConfig((current) => {
17180
17327
  const existing = current.outputs?.[uuid];
@@ -17193,6 +17340,13 @@ var OutputDisplay = ({
17193
17340
  };
17194
17341
  });
17195
17342
  }, [uuid, updateConfig]);
17343
+ const rootState = (0, import_react32.useMemo)(
17344
+ () => ({
17345
+ errors: applicationState.outputs[uuid]?.errors ?? [],
17346
+ warnings: applicationState.outputs[uuid]?.warnings ?? []
17347
+ }),
17348
+ [applicationState.outputs, uuid]
17349
+ );
17196
17350
  return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
17197
17351
  "div",
17198
17352
  {
@@ -17211,23 +17365,25 @@ var OutputDisplay = ({
17211
17365
  type: STRINGS.protocols[config.definition.type].short,
17212
17366
  name: config.name ? [config.name] : [],
17213
17367
  color: config.color,
17214
- timecode: config.enabled ? timecode : null,
17215
- namePlaceholder: `Unnamed Output`,
17368
+ timecode: config.enabled ? timecode : "disabled",
17369
+ rootState,
17370
+ namePlaceholder: STRINGS.outputs.unnamed,
17371
+ link,
17216
17372
  buttons: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
17217
17373
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
17218
17374
  ControlButton,
17219
17375
  {
17220
17376
  variant: "large",
17221
- title: config.enabled ? "Stop Input" : "Start Input",
17377
+ title: config.enabled ? STRINGS.outputs.disable : STRINGS.outputs.enable,
17222
17378
  onClick: toggleEnabled,
17223
- icon: config.enabled ? "stop" : "play_arrow"
17379
+ icon: config.enabled ? "pause" : "play_arrow"
17224
17380
  }
17225
17381
  ),
17226
17382
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
17227
17383
  ControlButton,
17228
17384
  {
17229
17385
  variant: "large",
17230
- title: "Link Output",
17386
+ title: STRINGS.outputs.link,
17231
17387
  active: assignToOutput === uuid,
17232
17388
  onClick: linkCallback,
17233
17389
  icon: config.link ? "link" : "link_off"
@@ -17237,7 +17393,7 @@ var OutputDisplay = ({
17237
17393
  ControlButton,
17238
17394
  {
17239
17395
  variant: "large",
17240
- title: "Edit Output",
17396
+ title: STRINGS.outputs.edit,
17241
17397
  onClick: () => setDialogMode({
17242
17398
  section: { type: "outputs", output: config.definition.type },
17243
17399
  target: { type: "edit", uuid }
@@ -17495,6 +17651,7 @@ var GeneratorDisplay = ({
17495
17651
  }) => {
17496
17652
  const { generators } = useApplicationState();
17497
17653
  const state = generators[uuid];
17654
+ const rootState = (0, import_react33.useMemo)(() => ({ errors: [], warnings: [] }), []);
17498
17655
  return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17499
17656
  TimecodeTreeDisplay,
17500
17657
  {
@@ -17504,12 +17661,13 @@ var GeneratorDisplay = ({
17504
17661
  name: config.name ? [config.name] : [],
17505
17662
  color: config.color,
17506
17663
  timecode: state?.timecode ?? null,
17507
- namePlaceholder: `Unnamed Generator`,
17664
+ rootState,
17665
+ namePlaceholder: STRINGS.generators.unnamed,
17508
17666
  buttons: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_jsx_runtime44.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
17509
17667
  ControlButton,
17510
17668
  {
17511
17669
  variant: "large",
17512
- title: "Edit Generator",
17670
+ title: STRINGS.generators.edit,
17513
17671
  onClick: () => setDialogMode({
17514
17672
  section: {
17515
17673
  type: "generators",
@@ -17898,6 +18056,10 @@ var InputDisplay = ({
17898
18056
  };
17899
18057
  });
17900
18058
  }, [uuid, updateConfig]);
18059
+ const rootState = (0, import_react34.useMemo)(
18060
+ () => ({ errors: state?.errors ?? [], warnings: state?.warnings ?? [] }),
18061
+ [state?.errors, state?.warnings]
18062
+ );
17901
18063
  return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
17902
18064
  TimecodeTreeDisplay,
17903
18065
  {
@@ -17906,23 +18068,24 @@ var InputDisplay = ({
17906
18068
  type: STRINGS.protocols[config.definition.type].short,
17907
18069
  name: config.name ? [config.name] : [],
17908
18070
  color: config.color,
17909
- timecode: state?.timecode ?? null,
17910
- namePlaceholder: `Unnamed Input`,
18071
+ timecode: config.enabled ? state?.timecode ?? null : "disabled",
18072
+ rootState,
18073
+ namePlaceholder: STRINGS.inputs.unnamed,
17911
18074
  buttons: /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_jsx_runtime45.Fragment, { children: [
17912
18075
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
17913
18076
  ControlButton,
17914
18077
  {
17915
18078
  variant: "large",
17916
- title: config.enabled ? "Stop Input" : "Start Input",
18079
+ title: config.enabled ? STRINGS.inputs.disable : STRINGS.inputs.enable,
17917
18080
  onClick: toggleEnabled,
17918
- icon: config.enabled ? "stop" : "play_arrow"
18081
+ icon: config.enabled ? "pause" : "play_arrow"
17919
18082
  }
17920
18083
  ),
17921
18084
  /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
17922
18085
  ControlButton,
17923
18086
  {
17924
18087
  variant: "large",
17925
- title: "Edit Input",
18088
+ title: STRINGS.inputs.edit,
17926
18089
  onClick: () => setDialogMode({
17927
18090
  section: { type: "inputs", input: config.definition.type },
17928
18091
  target: { type: "edit", uuid }