@hashintel/ds-theme 0.1.0 → 0.1.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @hashintel/ds-theme
2
2
 
3
+ ## 0.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#8590](https://github.com/hashintel/hash/pull/8590) [`4a60112`](https://github.com/hashintel/hash/commit/4a6011241720a9c5d8a7f0e7f49f15b50eaad228) Thanks [@CiaranMn](https://github.com/CiaranMn)! - provide theme scoping utility function
8
+
9
+ ## 0.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#8570](https://github.com/hashintel/hash/pull/8570) [`2399453`](https://github.com/hashintel/hash/commit/23994530e745c153a2b926c89e9205b87630c236) Thanks [@CiaranMn](https://github.com/CiaranMn)! - Fix dependency references
14
+
3
15
  ## 0.1.0
4
16
 
5
17
  ### Minor Changes
package/dist/main.d.ts CHANGED
@@ -21813,17 +21813,61 @@ interface ExtendableOptions {
21813
21813
  */
21814
21814
  themes?: ExtendableThemeVariantsMap;
21815
21815
  }
21816
- interface PresetOptions {
21816
+ interface PresetOptions$1 {
21817
21817
  /**
21818
21818
  * Used to create reusable config presets for your project or team.
21819
21819
  */
21820
21820
  presets?: (string | Preset | Promise<Preset>)[];
21821
21821
  }
21822
- interface Preset extends ExtendableOptions, PresetOptions {
21822
+ interface Preset extends ExtendableOptions, PresetOptions$1 {
21823
21823
  name: string;
21824
21824
  }
21825
21825
  //#endregion
21826
21826
  //#region src/main.d.ts
21827
+ type PresetOptions = {
21828
+ /**
21829
+ * Scope the preset's global styles and light/dark conditions to a subtree
21830
+ * instead of the document root. When set, globalCss targets this selector
21831
+ * (instead of `html, body`) and includes `fontPipelineCssVars` so that
21832
+ * preflight and token vars resolve correctly within the subtree.
21833
+ *
21834
+ * @example ".petrinaut-root"
21835
+ */
21836
+ scope?: string;
21837
+ };
21838
+ /**
21839
+ * Create the `@hashintel/ds-theme` Panda CSS preset.
21840
+ *
21841
+ * Without arguments it behaves identically to the default export (document-level
21842
+ * global styles). Pass `{ scope }` to target a subtree instead.
21843
+ */
21844
+ declare function createPreset(options?: PresetOptions): Preset;
21845
+ /**
21846
+ * Returns the Panda config properties needed to scope the design system to a
21847
+ * CSS subtree. Spread the result into `defineConfig()`.
21848
+ *
21849
+ * Handles `preflight`, `cssVarRoot`, `presets`, and scoped `conditions` /
21850
+ * `globalCss` inside the preset — the consumer only needs to add their own
21851
+ * `include`, `theme.extend`, etc.
21852
+ *
21853
+ * @example
21854
+ * ```ts
21855
+ * import { defineConfig } from "@pandacss/dev";
21856
+ * import { scopedThemeConfig } from "@hashintel/ds-theme";
21857
+ *
21858
+ * export default defineConfig({
21859
+ * ...scopedThemeConfig(".my-root"),
21860
+ * include: ["./src/**\/*.{ts,tsx}"],
21861
+ * });
21862
+ * ```
21863
+ */
21864
+ declare function scopedThemeConfig(scope: string): {
21865
+ preflight: {
21866
+ readonly scope: string;
21867
+ };
21868
+ cssVarRoot: string;
21869
+ presets: Preset[];
21870
+ };
21827
21871
  declare const preset: Preset;
21828
21872
  //#endregion
21829
- export { preset as default, preset };
21873
+ export { PresetOptions, createPreset, preset as default, preset, scopedThemeConfig };
package/dist/main.js CHANGED
@@ -615,6 +615,47 @@ var index_default = definePreset({
615
615
  }
616
616
  });
617
617
  //#endregion
618
+ //#region src/document-surface.ts
619
+ /**
620
+ * CSS variables that bridge Panda's preflight (which uses `--global-font-body`
621
+ * / `--global-font-mono`) with the generated `--fonts-*` token vars.
622
+ *
623
+ * In a full-page app these live on `:root` (see ds-helpers Ladle CSS).
624
+ * When the theme is scoped to a subtree, the preset places them on the scope
625
+ * root so preflight can resolve them.
626
+ *
627
+ * `--global-font-body` and `--global-font-mono` reference the Panda token vars
628
+ * (`--fonts-body`, `--fonts-mono`), so they automatically reflect whatever the
629
+ * consumer sets for `fonts.body` / `fonts.mono` — no separate override needed.
630
+ *
631
+ * `--font-inter` / `--font-inter-tight` are the raw variable-font stacks that
632
+ * the token definitions reference (`fonts.body` = `var(--font-inter), …`).
633
+ * Consumers must import the corresponding `@fontsource-variable/*` packages
634
+ * so the `@font-face` rules exist.
635
+ */
636
+ const fontPipelineCssVars = {
637
+ "--font-inter": "\"Inter Variable\", \"Inter\", ui-sans-serif, system-ui, sans-serif",
638
+ "--font-inter-tight": "\"Inter Tight Variable\", \"Inter Tight\", ui-sans-serif, system-ui, sans-serif",
639
+ "--global-font-body": "var(--fonts-body)",
640
+ "--global-font-mono": "var(--fonts-mono)"
641
+ };
642
+ /**
643
+ * Default document surface styles applied to `html, body` by the preset.
644
+ *
645
+ * Sets the default color palette, font family, background, text color, and
646
+ * the density / roundness / leading factor custom properties.
647
+ */
648
+ const documentSurfaceStyles = {
649
+ colorPalette: "neutral",
650
+ focusRingColor: "colorPalette.bd.solid",
651
+ fontFamily: "body",
652
+ bg: "neutral.s00",
653
+ color: "fg.heading",
654
+ "--roundness-factor": "1",
655
+ "--leading-factor": "1",
656
+ "--density-factor": "1"
657
+ };
658
+ //#endregion
618
659
  //#region src/theme/utils.ts
619
660
  /**
620
661
  * Returns the foreground color to use on a "solid" background (bg.solid / bgSolid.solid).
@@ -779,179 +820,213 @@ const scaleTokenValues = (tokens, factorVariable, { skipReferences = false } = {
779
820
  const scaledSpacing = scaleTokenValues(index_default.theme.tokens.spacing, "--density-factor");
780
821
  const scaledRadii = scaleTokenValues(index_default.theme.tokens.radii, "--roundness-factor");
781
822
  const scaledLineHeights = scaleTokenValues(index_default.theme.tokens.lineHeights, "--leading-factor");
782
- const preset = definePreset$1({
783
- name: "@hashintel/ds-theme",
784
- globalCss: defineGlobalStyles({ "html, body": {
785
- colorPalette: "neutral",
786
- focusRingColor: "colorPalette.bd.solid",
787
- fontFamily: "body",
788
- bg: "neutral.s00",
789
- color: "fg.heading",
790
- "--roundness-factor": "1",
791
- "--leading-factor": "1",
792
- "--density-factor": "1"
793
- } }),
794
- conditions: { extend: {
795
- light: ":where(:root:not(.dark, [data-theme=\"dark\"])) &, .light &, [data-theme=light] &",
796
- dark: ".dark &, [data-theme=\"dark\"] &",
797
- supportHover: ["@media (hover: hover) and (pointer: fine)", "&:is(:hover, [data-support-hover])"],
798
- focusVisibleWithin: "&:is(:has(:focus-visible), [data-focus-visible-within])",
799
- inert: "&:is([inert], [inert] *, [data-inert])",
800
- groupFocusVisibleWithin: ".group:is(:has(:focus-visible), [data-focus-visible-within]) &",
801
- peerFocusVisibleWithin: ".peer:is(:has(:focus-visible), [data-focus-visible-within]) ~ &",
802
- userValid: "&:is(:user-valid, [data-user-valid])",
803
- userInvalid: "&:is(:user-invalid, [data-user-invalid])",
804
- pointerFine: "@media (pointer: fine)",
805
- pointerCoarse: "@media (pointer: coarse)",
806
- pointerNone: "@media (pointer: none)",
807
- anyPointerFine: "@media (any-pointer: fine)",
808
- anyPointerCoarse: "@media (any-pointer: coarse)",
809
- inHover: ":where(:is(*:hover, [data-in-hover])) &",
810
- inFocus: ":where(:is(*:focus, [data-in-focus])) &",
811
- inFocusVisible: ":where(:is(*:focus-visible, [data-in-focus-visible])) &",
812
- inFocusWithin: ":where(:is(*:focus-within, [data-in-focus-within])) &",
813
- hasHover: "&:is(:has(*:hover), [data-has-hover])",
814
- hasFocus: "&:is(:has(*:focus), [data-has-focus])",
815
- hasFocusVisible: "&:is(:has(*:focus-visible), [data-has-focus-visible])",
816
- hasFocusWithin: "&:is(:has(*:focus-within), [data-has-focus-within])",
817
- hasChecked: "&:is(:has(*:checked), [data-has-checked])"
818
- } },
819
- utilities: { extend: {
820
- leading: {
821
- className: "leading",
822
- values: {
823
- tight: "0.9",
824
- normal: "1",
825
- loose: "1.1"
826
- },
827
- transform(value) {
828
- return { "--leading-factor": value };
829
- }
830
- },
831
- density: {
832
- className: "density",
833
- values: {
834
- compact: "0.75",
835
- normal: "1",
836
- comfortable: "1.25"
837
- },
838
- transform(value) {
839
- return { "--density-factor": value };
840
- }
841
- },
842
- roundness: {
843
- className: "roundness",
844
- values: {
845
- none: "0",
846
- sm: "0.75",
847
- md: "1",
848
- lg: "1.5",
849
- xl: "2"
850
- },
851
- transform(value) {
852
- return { "--roundness-factor": value };
853
- }
854
- }
855
- } },
856
- theme: { extend: {
857
- tokens: {
858
- fontSizes: fontSizes$1,
859
- fontWeights: fontWeights$1,
860
- fonts: {
861
- display: { value: "var(--font-inter-tight), Inter Tight, ui-sans-serif, system-ui, sans-serif" },
862
- body: { value: "var(--font-inter), Inter, ui-sans-serif, system-ui, sans-serif" },
863
- mono: { value: "var(--font-geist-mono), Geist Mono, ui-monospace, SFMono-Regular, monospace" }
823
+ /**
824
+ * Create the `@hashintel/ds-theme` Panda CSS preset.
825
+ *
826
+ * Without arguments it behaves identically to the default export (document-level
827
+ * global styles). Pass `{ scope }` to target a subtree instead.
828
+ */
829
+ function createPreset(options) {
830
+ const scope = options?.scope;
831
+ const surfaceSelector = scope ?? "html, body";
832
+ const surfaceStyles = scope ? {
833
+ ...fontPipelineCssVars,
834
+ ...documentSurfaceStyles
835
+ } : documentSurfaceStyles;
836
+ const lightCondition = scope ? `${scope} &` : ":where(:root:not(.dark, [data-theme=\"dark\"])) &, .light &, [data-theme=light] &";
837
+ const darkCondition = scope ? `.dark ${scope} &, [data-theme='dark'] ${scope} &` : ".dark &, [data-theme=\"dark\"] &";
838
+ return definePreset$1({
839
+ name: "@hashintel/ds-theme",
840
+ globalCss: defineGlobalStyles({ [surfaceSelector]: surfaceStyles }),
841
+ conditions: { extend: {
842
+ light: lightCondition,
843
+ dark: darkCondition,
844
+ supportHover: ["@media (hover: hover) and (pointer: fine)", "&:is(:hover, [data-support-hover])"],
845
+ focusVisibleWithin: "&:is(:has(:focus-visible), [data-focus-visible-within])",
846
+ inert: "&:is([inert], [inert] *, [data-inert])",
847
+ groupFocusVisibleWithin: ".group:is(:has(:focus-visible), [data-focus-visible-within]) &",
848
+ peerFocusVisibleWithin: ".peer:is(:has(:focus-visible), [data-focus-visible-within]) ~ &",
849
+ userValid: "&:is(:user-valid, [data-user-valid])",
850
+ userInvalid: "&:is(:user-invalid, [data-user-invalid])",
851
+ pointerFine: "@media (pointer: fine)",
852
+ pointerCoarse: "@media (pointer: coarse)",
853
+ pointerNone: "@media (pointer: none)",
854
+ anyPointerFine: "@media (any-pointer: fine)",
855
+ anyPointerCoarse: "@media (any-pointer: coarse)",
856
+ inHover: ":where(:is(*:hover, [data-in-hover])) &",
857
+ inFocus: ":where(:is(*:focus, [data-in-focus])) &",
858
+ inFocusVisible: ":where(:is(*:focus-visible, [data-in-focus-visible])) &",
859
+ inFocusWithin: ":where(:is(*:focus-within, [data-in-focus-within])) &",
860
+ hasHover: "&:is(:has(*:hover), [data-has-hover])",
861
+ hasFocus: "&:is(:has(*:focus), [data-has-focus])",
862
+ hasFocusVisible: "&:is(:has(*:focus-visible), [data-has-focus-visible])",
863
+ hasFocusWithin: "&:is(:has(*:focus-within), [data-has-focus-within])",
864
+ hasChecked: "&:is(:has(*:checked), [data-has-checked])"
865
+ } },
866
+ utilities: { extend: {
867
+ leading: {
868
+ className: "leading",
869
+ values: {
870
+ tight: "0.9",
871
+ normal: "1",
872
+ loose: "1.1"
873
+ },
874
+ transform(value) {
875
+ return { "--leading-factor": value };
876
+ }
864
877
  },
865
- colors: staticColors,
866
- sizes: index_default.theme.tokens.sizes,
867
- shadows: index_default.theme.tokens.shadows,
868
- spacing: scaledSpacing,
869
- radii: scaledRadii,
870
- lineHeights: scaledLineHeights
871
- },
872
- semanticTokens: {
873
- colors: {
874
- DEFAULT: createSemanticSet("colors.neutral", "neutral"),
875
- ...palettes,
876
- status: {
877
- info: blue,
878
- success: green,
879
- warning: orange,
880
- error: red
878
+ density: {
879
+ className: "density",
880
+ values: {
881
+ compact: "0.75",
882
+ normal: "1",
883
+ comfortable: "1.25"
884
+ },
885
+ transform(value) {
886
+ return { "--density-factor": value };
881
887
  }
882
888
  },
883
- shadows: { elevation: {
884
- drop: {
885
- macro: { value: "{shadows.xs}" },
886
- micro: { value: "{shadows.2xs}" }
889
+ roundness: {
890
+ className: "roundness",
891
+ values: {
892
+ none: "0",
893
+ sm: "0.75",
894
+ md: "1",
895
+ lg: "1.5",
896
+ xl: "2"
887
897
  },
888
- lift: {
889
- macro: { value: "{shadows.sm}" },
890
- micro: { value: "{shadows.xs}" }
898
+ transform(value) {
899
+ return { "--roundness-factor": value };
900
+ }
901
+ }
902
+ } },
903
+ theme: { extend: {
904
+ tokens: {
905
+ fontSizes: fontSizes$1,
906
+ fontWeights: fontWeights$1,
907
+ fonts: {
908
+ display: { value: "var(--font-inter-tight), Inter Tight, ui-sans-serif, system-ui, sans-serif" },
909
+ body: { value: "var(--font-inter), Inter, ui-sans-serif, system-ui, sans-serif" },
910
+ mono: { value: "var(--font-geist-mono), Geist Mono, ui-monospace, SFMono-Regular, monospace" }
891
911
  },
892
- raise: {
893
- macro: { value: "{shadows.md}" },
894
- micro: { value: "{shadows.sm}" }
912
+ colors: staticColors,
913
+ sizes: index_default.theme.tokens.sizes,
914
+ shadows: index_default.theme.tokens.shadows,
915
+ spacing: scaledSpacing,
916
+ radii: scaledRadii,
917
+ lineHeights: scaledLineHeights
918
+ },
919
+ semanticTokens: {
920
+ colors: {
921
+ DEFAULT: createSemanticSet("colors.neutral", "neutral"),
922
+ ...palettes,
923
+ status: {
924
+ info: blue,
925
+ success: green,
926
+ warning: orange,
927
+ error: red
928
+ }
895
929
  },
896
- float: {
897
- macro: { value: "{shadows.lg}" },
898
- micro: { value: "{shadows.md}" }
899
- }
900
- } }
901
- },
902
- textStyles: {
903
- xs: { value: {
904
- fontSize: "{fontSizes.xs}",
905
- lineHeight: "calc(1em * 1.6 * var(--leading-factor, 1))",
906
- letterSpacing: "0.01em"
907
- } },
908
- sm: { value: {
909
- fontSize: "{fontSizes.sm}",
910
- lineHeight: "calc(1em * 1.6 * var(--leading-factor, 1))",
911
- letterSpacing: "0.005em"
912
- } },
913
- base: { value: {
914
- fontSize: "{fontSizes.base}",
915
- lineHeight: "calc(1em * 1.5 * var(--leading-factor, 1))",
916
- letterSpacing: "0em"
917
- } },
918
- lg: { value: {
919
- fontSize: "{fontSizes.lg}",
920
- lineHeight: "calc(1em * 1.5 * var(--leading-factor, 1))",
921
- letterSpacing: "-0.005em"
922
- } },
923
- xl: { value: {
924
- fontSize: "{fontSizes.xl}",
925
- lineHeight: "calc(1em * 1.4 * var(--leading-factor, 1))",
926
- letterSpacing: "-0.01em"
927
- } },
928
- "2xl": { value: {
929
- fontSize: "{fontSizes.2xl}",
930
- lineHeight: "calc(1em * 1.4 * var(--leading-factor, 1))",
931
- letterSpacing: "-0.015em"
932
- } },
933
- "3xl": { value: {
934
- fontSize: "{fontSizes.3xl}",
935
- lineHeight: "calc(1em * 1.3 * var(--leading-factor, 1))",
936
- letterSpacing: "-0.02em"
937
- } },
938
- "4xl": { value: {
939
- fontSize: "{fontSizes.4xl}",
940
- lineHeight: "calc(1em * 1.3 * var(--leading-factor, 1))",
941
- letterSpacing: "-0.025em"
942
- } }
943
- },
944
- colorPalette: {
945
- enabled: true,
946
- include: [
947
- "bg.*",
948
- "bgSolid.*",
949
- "fg.*",
950
- "bd.*",
951
- "status.*"
952
- ]
953
- }
954
- } }
955
- });
930
+ shadows: { elevation: {
931
+ drop: {
932
+ macro: { value: "{shadows.xs}" },
933
+ micro: { value: "{shadows.2xs}" }
934
+ },
935
+ lift: {
936
+ macro: { value: "{shadows.sm}" },
937
+ micro: { value: "{shadows.xs}" }
938
+ },
939
+ raise: {
940
+ macro: { value: "{shadows.md}" },
941
+ micro: { value: "{shadows.sm}" }
942
+ },
943
+ float: {
944
+ macro: { value: "{shadows.lg}" },
945
+ micro: { value: "{shadows.md}" }
946
+ }
947
+ } }
948
+ },
949
+ textStyles: {
950
+ xs: { value: {
951
+ fontSize: "{fontSizes.xs}",
952
+ lineHeight: "calc(1em * 1.6 * var(--leading-factor, 1))",
953
+ letterSpacing: "0.01em"
954
+ } },
955
+ sm: { value: {
956
+ fontSize: "{fontSizes.sm}",
957
+ lineHeight: "calc(1em * 1.6 * var(--leading-factor, 1))",
958
+ letterSpacing: "0.005em"
959
+ } },
960
+ base: { value: {
961
+ fontSize: "{fontSizes.base}",
962
+ lineHeight: "calc(1em * 1.5 * var(--leading-factor, 1))",
963
+ letterSpacing: "0em"
964
+ } },
965
+ lg: { value: {
966
+ fontSize: "{fontSizes.lg}",
967
+ lineHeight: "calc(1em * 1.5 * var(--leading-factor, 1))",
968
+ letterSpacing: "-0.005em"
969
+ } },
970
+ xl: { value: {
971
+ fontSize: "{fontSizes.xl}",
972
+ lineHeight: "calc(1em * 1.4 * var(--leading-factor, 1))",
973
+ letterSpacing: "-0.01em"
974
+ } },
975
+ "2xl": { value: {
976
+ fontSize: "{fontSizes.2xl}",
977
+ lineHeight: "calc(1em * 1.4 * var(--leading-factor, 1))",
978
+ letterSpacing: "-0.015em"
979
+ } },
980
+ "3xl": { value: {
981
+ fontSize: "{fontSizes.3xl}",
982
+ lineHeight: "calc(1em * 1.3 * var(--leading-factor, 1))",
983
+ letterSpacing: "-0.02em"
984
+ } },
985
+ "4xl": { value: {
986
+ fontSize: "{fontSizes.4xl}",
987
+ lineHeight: "calc(1em * 1.3 * var(--leading-factor, 1))",
988
+ letterSpacing: "-0.025em"
989
+ } }
990
+ },
991
+ colorPalette: {
992
+ enabled: true,
993
+ include: [
994
+ "bg.*",
995
+ "bgSolid.*",
996
+ "fg.*",
997
+ "bd.*",
998
+ "status.*"
999
+ ]
1000
+ }
1001
+ } }
1002
+ });
1003
+ }
1004
+ /**
1005
+ * Returns the Panda config properties needed to scope the design system to a
1006
+ * CSS subtree. Spread the result into `defineConfig()`.
1007
+ *
1008
+ * Handles `preflight`, `cssVarRoot`, `presets`, and scoped `conditions` /
1009
+ * `globalCss` inside the preset — the consumer only needs to add their own
1010
+ * `include`, `theme.extend`, etc.
1011
+ *
1012
+ * @example
1013
+ * ```ts
1014
+ * import { defineConfig } from "@pandacss/dev";
1015
+ * import { scopedThemeConfig } from "@hashintel/ds-theme";
1016
+ *
1017
+ * export default defineConfig({
1018
+ * ...scopedThemeConfig(".my-root"),
1019
+ * include: ["./src/**\/*.{ts,tsx}"],
1020
+ * });
1021
+ * ```
1022
+ */
1023
+ function scopedThemeConfig(scope) {
1024
+ return {
1025
+ preflight: { scope },
1026
+ cssVarRoot: scope,
1027
+ presets: [createPreset({ scope })]
1028
+ };
1029
+ }
1030
+ const preset = createPreset();
956
1031
  //#endregion
957
- export { preset as default, preset };
1032
+ export { createPreset, preset as default, preset, scopedThemeConfig };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hashintel/ds-theme",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "HASH PandaCSS Preset",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "repository": {
@@ -45,7 +45,7 @@
45
45
  "fix:format": "biome format --write",
46
46
  "lint": "npm-run-all --continue-on-error \"lint:*\"",
47
47
  "lint:tsc": "tsc --noEmit && tsc --noEmit -p scripts/tsconfig.json",
48
- "prepare": "turbo run build",
48
+ "prepublishOnly": "turbo run build",
49
49
  "test:unit": "vitest run"
50
50
  },
51
51
  "devDependencies": {