@fristil/designsystem 0.5.1 → 0.5.3

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 (74) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/dist/components/css/select/select.d.ts +18 -1
  3. package/dist/components/css/select/select.d.ts.map +1 -1
  4. package/dist/components/css/select/select.js +15 -2
  5. package/dist/components/css/select/select.js.map +1 -1
  6. package/dist/components/frittstaende/connection-status/fs-connection-status.d.ts +2 -1
  7. package/dist/components/frittstaende/connection-status/fs-connection-status.d.ts.map +1 -1
  8. package/dist/components/frittstaende/connection-status/fs-connection-status.js +3 -4
  9. package/dist/components/frittstaende/connection-status/fs-connection-status.js.map +1 -1
  10. package/dist/components/frittstaende/session-timeout/fs-session-timeout.d.ts +2 -1
  11. package/dist/components/frittstaende/session-timeout/fs-session-timeout.d.ts.map +1 -1
  12. package/dist/components/frittstaende/session-timeout/fs-session-timeout.js +3 -4
  13. package/dist/components/frittstaende/session-timeout/fs-session-timeout.js.map +1 -1
  14. package/dist/components/frittstaende/toast/fs-toast.d.ts +2 -1
  15. package/dist/components/frittstaende/toast/fs-toast.d.ts.map +1 -1
  16. package/dist/components/frittstaende/toast/fs-toast.js +3 -4
  17. package/dist/components/frittstaende/toast/fs-toast.js.map +1 -1
  18. package/dist/components/host-element.d.ts +28 -0
  19. package/dist/components/host-element.d.ts.map +1 -0
  20. package/dist/components/host-element.js +33 -0
  21. package/dist/components/host-element.js.map +1 -0
  22. package/dist/components/ramme/error-summary/fs-error-summary.d.ts +2 -1
  23. package/dist/components/ramme/error-summary/fs-error-summary.d.ts.map +1 -1
  24. package/dist/components/ramme/error-summary/fs-error-summary.js +15 -7
  25. package/dist/components/ramme/error-summary/fs-error-summary.js.map +1 -1
  26. package/dist/components/ramme/field/field-core.d.ts +15 -6
  27. package/dist/components/ramme/field/field-core.d.ts.map +1 -1
  28. package/dist/components/ramme/field/field-core.js +15 -6
  29. package/dist/components/ramme/field/field-core.js.map +1 -1
  30. package/dist/components/ramme/field/fs-field.d.ts +2 -1
  31. package/dist/components/ramme/field/fs-field.d.ts.map +1 -1
  32. package/dist/components/ramme/field/fs-field.js +3 -4
  33. package/dist/components/ramme/field/fs-field.js.map +1 -1
  34. package/dist/components/ramme/popover/fs-popover.d.ts +2 -1
  35. package/dist/components/ramme/popover/fs-popover.d.ts.map +1 -1
  36. package/dist/components/ramme/popover/fs-popover.js +3 -4
  37. package/dist/components/ramme/popover/fs-popover.js.map +1 -1
  38. package/dist/components/ramme/suggestion/fs-suggestion.d.ts +13 -2
  39. package/dist/components/ramme/suggestion/fs-suggestion.d.ts.map +1 -1
  40. package/dist/components/ramme/suggestion/fs-suggestion.js +27 -8
  41. package/dist/components/ramme/suggestion/fs-suggestion.js.map +1 -1
  42. package/dist/components/ramme/suggestion/suggestion.d.ts +10 -0
  43. package/dist/components/ramme/suggestion/suggestion.d.ts.map +1 -1
  44. package/dist/components/ramme/suggestion/suggestion.js +13 -1
  45. package/dist/components/ramme/suggestion/suggestion.js.map +1 -1
  46. package/dist/components/ramme/tabs/fs-tabs.d.ts +2 -1
  47. package/dist/components/ramme/tabs/fs-tabs.d.ts.map +1 -1
  48. package/dist/components/ramme/tabs/fs-tabs.js +3 -4
  49. package/dist/components/ramme/tabs/fs-tabs.js.map +1 -1
  50. package/dist/dom.d.ts.map +1 -1
  51. package/dist/dom.js +2 -0
  52. package/dist/dom.js.map +1 -1
  53. package/dist/fs.d.ts +5 -1
  54. package/dist/fs.d.ts.map +1 -1
  55. package/dist/index.d.ts +2 -2
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +1 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/react.d.ts +5 -1
  60. package/dist/react.d.ts.map +1 -1
  61. package/package.json +7 -2
  62. package/src/components/css/select/select.css +193 -5
  63. package/src/components/css/select/select.ts +24 -1
  64. package/src/components/frittstaende/connection-status/fs-connection-status.ts +3 -4
  65. package/src/components/frittstaende/session-timeout/fs-session-timeout.ts +3 -4
  66. package/src/components/frittstaende/toast/fs-toast.ts +3 -4
  67. package/src/components/host-element.ts +34 -0
  68. package/src/components/ramme/error-summary/fs-error-summary.ts +16 -7
  69. package/src/components/ramme/field/field-core.ts +15 -6
  70. package/src/components/ramme/field/fs-field.ts +3 -4
  71. package/src/components/ramme/popover/fs-popover.ts +3 -4
  72. package/src/components/ramme/suggestion/fs-suggestion.ts +30 -8
  73. package/src/components/ramme/suggestion/suggestion.ts +13 -1
  74. package/src/components/ramme/tabs/fs-tabs.ts +3 -4
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAMnE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAOvD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,6CAA6C,CAAA;AAMzE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAKpD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAM7D,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAOrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAKxE,OAAO,EAAE,UAAU,EAAE,MAAM,6CAA6C,CAAA;AAMxE,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAM7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAA;AAMlE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAKvD,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAMpD,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,2CAA2C,CAAA;AAOtE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAKnE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAKvD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAK1D,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAC1D,cAAc,4BAA4B,CAAA;AAM1C,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAA;AAMlE,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAA;AAK5D,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AAMjE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAMvD,OAAO,EAAE,GAAG,EAAE,MAAM,6BAA6B,CAAA;AAKjD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,+CAA+C,CAAA;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAC7D,cAAc,kEAAkE,CAAA;AAChF,cAAc,qEAAqE,CAAA;AACnF,cAAc,iEAAiE,CAAA;AAC/E,cAAc,8DAA8D,CAAA;AAC5E,cAAc,6CAA6C,CAAA;AAC3D,cAAc,0CAA0C,CAAA;AACxD,cAAc,mDAAmD,CAAA;AACjE,cAAc,sDAAsD,CAAA;AACpE,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,0CAA0C,CAAA;AACxD,cAAc,uCAAuC,CAAA;AACrD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,oCAAoC,CAAA;AAClD,cAAc,iCAAiC,CAAA;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,cAAc,oBAAoB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAMnE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAOvD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,6CAA6C,CAAA;AAMzE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAKpD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAM1D,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAM7D,OAAO,EAAE,SAAS,EAAE,MAAM,2CAA2C,CAAA;AAOrE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAKxE,OAAO,EAAE,UAAU,EAAE,MAAM,6CAA6C,CAAA;AAMxE,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAM7D,OAAO,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAA;AAMlE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAKvD,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAMpD,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,2CAA2C,CAAA;AAOtE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAKnE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAKvD,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAA;AAO1D,OAAO,EACL,cAAc,EACd,MAAM,EACN,aAAa,GACd,MAAM,mCAAmC,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAM1C,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAA;AAMlE,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAE7D,OAAO,EAAE,MAAM,EAAE,MAAM,qCAAqC,CAAA;AAK5D,OAAO,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAA;AAMjE,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAA;AAMvD,OAAO,EAAE,GAAG,EAAE,MAAM,6BAA6B,CAAA;AAKjD,OAAO,EAAE,QAAQ,EAAE,MAAM,uCAAuC,CAAA;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,+CAA+C,CAAA;AAE3E,OAAO,EAAE,OAAO,EAAE,MAAM,qCAAqC,CAAA;AAC7D,cAAc,kEAAkE,CAAA;AAChF,cAAc,qEAAqE,CAAA;AACnF,cAAc,iEAAiE,CAAA;AAC/E,cAAc,8DAA8D,CAAA;AAC5E,cAAc,6CAA6C,CAAA;AAC3D,cAAc,0CAA0C,CAAA;AACxD,cAAc,mDAAmD,CAAA;AACjE,cAAc,sDAAsD,CAAA;AACpE,cAAc,wCAAwC,CAAA;AACtD,cAAc,sCAAsC,CAAA;AACpD,cAAc,0CAA0C,CAAA;AACxD,cAAc,uCAAuC,CAAA;AACrD,cAAc,gDAAgD,CAAA;AAC9D,cAAc,6CAA6C,CAAA;AAC3D,cAAc,oCAAoC,CAAA;AAClD,cAAc,iCAAiC,CAAA;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,cAAc,oBAAoB,CAAA"}
package/dist/react.d.ts CHANGED
@@ -137,9 +137,11 @@ export declare const fs: {
137
137
  states: readonly ["default", "invalid", "success"];
138
138
  isState: (value: string) => value is "default" | "success" | "invalid";
139
139
  };
140
- readonly select: ((options?: import("./index.js").SelectOptions | undefined) => ReactAttributes<import("./index.js").SelectAttributes>) & (({ state }?: import("./index.js").SelectOptions) => import("./index.js").SelectAttributes) & {
140
+ readonly select: ((options?: import("./index.js").SelectOptions | undefined) => ReactAttributes<import("./index.js").SelectAttributes>) & (({ state, picker, }?: import("./index.js").SelectOptions) => import("./index.js").SelectAttributes) & {
141
141
  states: readonly ["default", "invalid", "success"];
142
142
  isState: (value: string) => value is "default" | "success" | "invalid";
143
+ pickers: readonly ["auto", "styled"];
144
+ isPicker: (value: string) => value is "auto" | "styled";
143
145
  };
144
146
  readonly skeleton: ((options?: import("./index.js").SkeletonOptions | undefined) => ReactAttributes<import("./index.js").SkeletonAttributes>) & (({ variant }?: import("./index.js").SkeletonOptions) => import("./index.js").SkeletonAttributes) & {
145
147
  variants: readonly ["block", "text", "circle"];
@@ -306,6 +308,8 @@ export declare const fs: {
306
308
  }>[];
307
309
  empty: ReactAttributes<{
308
310
  class: "fs-suggestion__empty";
311
+ hidden: true | undefined;
312
+ "data-preserve-attr": "hidden";
309
313
  }>;
310
314
  status: ReactAttributes<{
311
315
  class: "fs-sr-only";
@@ -1 +1 @@
1
- {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,KAAK,EAAE,MAAM,0CAA0C,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mDAAmD,CAAA;AAChF,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,uCAAuC,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,6CAA6C,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,2CAA2C;AAC3C,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAC9B,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,OAAO,GAC9B,WAAW,GACX,CAAC,SAAS,KAAK,GACb,SAAS,GACT,CAAC,SAAS,UAAU,GAClB,UAAU,GACV,CAAC,SAAS,cAAc,GACtB,cAAc,GACd,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACnB,CAAA;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,UAAU,EAAE,CAAC,GACZ,eAAe,CAAC,CAAC,CAAC,CAMpB;AAgBD,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqCb;;;;;OAKG;+BACc,YAAY;;;;;;;;;;8BAlJjB,CAAC;0BACR,CAAA;wBAAyB,CAAC;oBAAwB,CAAC;;;;;;;kBACF,CAAC;;;;IAqJvD;;;;OAIG;sCACqB,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;gCAQvC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;6BAShC,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;mCASpB,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAcrC,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;CAkBpC,CAAA"}
1
+ {"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AA0CA,OAAO,EAAE,KAAK,EAAE,MAAM,0CAA0C,CAAA;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,mDAAmD,CAAA;AAChF,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,uCAAuC,CAAA;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,6CAA6C,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,iCAAiC,CAAA;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,2CAA2C;AAC3C,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;KAC9B,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,OAAO,GAC9B,WAAW,GACX,CAAC,SAAS,KAAK,GACb,SAAS,GACT,CAAC,SAAS,UAAU,GAClB,UAAU,GACV,CAAC,SAAS,cAAc,GACtB,cAAc,GACd,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACnB,CAAA;AAqBD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,UAAU,EAAE,CAAC,GACZ,eAAe,CAAC,CAAC,CAAC,CAMpB;AAgBD,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqCb;;;;;OAKG;+BACc,YAAY;;;;;;;;;;8BAlJjB,CAAC;0BACR,CAAA;wBAAyB,CAAC;oBAAwB,CAAC;;;;;;;kBACF,CAAC;;;;IAqJvD;;;;OAIG;sCACqB,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;gCAQvC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;6BAShC,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;mCASpB,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAcrC,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;CAkBpC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fristil/designsystem",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Rammeverksuavhengig designsystem: tokens, CSS-komponenter og web components.",
5
5
  "license": "MIT",
6
6
  "author": "MarkusAugust",
@@ -196,6 +196,10 @@
196
196
  "types": "./dist/dom.d.ts",
197
197
  "import": "./dist/dom.js"
198
198
  },
199
+ "./host-element": {
200
+ "types": "./dist/components/host-element.d.ts",
201
+ "import": "./dist/components/host-element.js"
202
+ },
199
203
  "./table.css": "./src/components/css/table/table.css",
200
204
  "./table": {
201
205
  "types": "./dist/components/css/table/table.d.ts",
@@ -297,11 +301,12 @@
297
301
  },
298
302
  "scripts": {
299
303
  "generate": "bun scripts/generate-tokens.ts",
300
- "build": "bun run generate && rm -rf dist && tsc -b --force && bun run sjekk:eksport && bun run sjekk:cli && bun run sjekk:versjon && bun run sjekk:pakke",
304
+ "build": "bun run generate && rm -rf dist && tsc -b --force && bun run sjekk:eksport && bun run sjekk:server && bun run sjekk:cli && bun run sjekk:versjon && bun run sjekk:pakke",
301
305
  "typecheck": "tsc --noEmit",
302
306
  "typecheck:tests": "tsc --noEmit -p tsconfig.tests.json",
303
307
  "test:browser": "vitest --config vitest.config.ts --run",
304
308
  "sjekk:eksport": "bun scripts/sjekk-eksport.ts",
309
+ "sjekk:server": "bun scripts/sjekk-server-import.ts",
305
310
  "sjekk:tailwind": "bun scripts/sjekk-tailwind.ts",
306
311
  "nettlesere": "playwright install chromium firefox webkit",
307
312
  "tema": "bun src/cli.ts",
@@ -7,8 +7,8 @@
7
7
 
8
8
  display: block;
9
9
  width: 100%;
10
- padding: var(--size-2) calc(var(--size-4) + var(--size-2)) var(--size-2)
11
- var(--size-3);
10
+ padding-block: var(--size-2);
11
+ padding-inline: var(--size-3) calc(var(--size-4) + var(--size-2));
12
12
  font-family: inherit;
13
13
  font-size: var(--font-size-m);
14
14
  line-height: 1.5;
@@ -37,6 +37,15 @@
37
37
  background-repeat: no-repeat;
38
38
  }
39
39
 
40
+ /* Pila er to gradienter, og `background-position` har ingen logisk
41
+ variant. Speilvendingen er de samme to bitene, flyttet til venstre kant
42
+ og byttet om: den som lå ytterst ligger nå innerst. */
43
+ .fs-select:dir(rtl) {
44
+ background-position:
45
+ calc(0.75rem - 0.35rem) calc(50% - 0.1rem),
46
+ calc(1rem - 0.35rem) calc(50% - 0.1rem);
47
+ }
48
+
40
49
  .fs-select:hover {
41
50
  border-color: var(--semantic-field-border-hover);
42
51
  }
@@ -83,13 +92,192 @@
83
92
  outline-color: var(--semantic-success-foreground);
84
93
  }
85
94
 
95
+ /*
96
+ * Nedtrekkslista er et vindu fra operativsystemet, og ingen CSS når inn i
97
+ * den. `appearance: base-select` ber nettleseren tegne den inne i siden i
98
+ * stedet: `::picker(select)` blir et vanlig element, og hvert `<option>`
99
+ * kan få systemets egne farger og avstander.
100
+ *
101
+ * Det er valgfritt, og slås på med `data-picker="styled"`. Firefox 150 har
102
+ * det ikke, og der beholder feltet nettleserens egen liste. Det er den
103
+ * samme komponenten med to utseender, ikke noe som går i stykker.
104
+ */
105
+ @supports (appearance: base-select) {
106
+ .fs-select[data-picker="styled"],
107
+ .fs-select[data-picker="styled"]::picker(select) {
108
+ appearance: base-select;
109
+ }
110
+
111
+ /* Knappen tegner nå sin egen pil med `::picker-icon`, så gradientene skal
112
+ bort. Pila tar ekte plass i oppsettet, og plassen vi holdt av til den
113
+ tegnede pila ville da blitt liggende dobbelt. */
114
+ .fs-select[data-picker="styled"] {
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: space-between;
118
+ gap: var(--size-2);
119
+ background-image: none;
120
+ padding-inline: var(--size-3);
121
+ }
122
+
123
+ /* Teksten i knappen er valget som står nå. Lange valg skal klippes, ikke
124
+ skyve pila ut av feltet. Uten `min-inline-size: 0` krymper den ikke,
125
+ for flex gir den minstebredden til innholdet. */
126
+ /* biome-ignore lint/correctness/noUnknownTypeSelector: <selectedcontent> er
127
+ elementet nettleseren lager for det valgte alternativet i en tilpassbar
128
+ nedtrekksliste. Biome kjenner det ennå ikke. */
129
+ .fs-select[data-picker="styled"] selectedcontent {
130
+ min-inline-size: 0;
131
+ overflow: hidden;
132
+ white-space: nowrap;
133
+ text-overflow: ellipsis;
134
+ }
135
+
136
+ .fs-select[data-picker="styled"]::picker-icon {
137
+ color: var(--semantic-muted-foreground);
138
+ transition: rotate 120ms ease;
139
+ }
140
+
141
+ .fs-select[data-picker="styled"]:open::picker-icon {
142
+ rotate: 180deg;
143
+ }
144
+
145
+ .fs-select[data-picker="styled"]::picker(select) {
146
+ box-sizing: border-box;
147
+ min-inline-size: anchor-size(self-inline);
148
+ /* Lista skal fylle plassen som faktisk er igjen ned til kanten av
149
+ vinduet, ikke strekke seg utenfor den. `stretch` er nettopp den
150
+ plassen, og margen trekkes fra. */
151
+ max-block-size: stretch;
152
+ margin-block: var(--fs-select-viewport-margin, var(--size-2));
153
+ padding: 0;
154
+ overflow-y: auto;
155
+ background: var(--semantic-page-background);
156
+ border: 1px solid var(--semantic-field-border);
157
+ border-radius: var(--fs-select-radius, var(--size-1));
158
+ box-shadow: var(--semantic-shadow-overlay);
159
+ /* Er det ikke plass under feltet, legges lista over det. */
160
+ position-try-fallbacks: flip-block;
161
+ opacity: 0;
162
+ transition:
163
+ opacity 120ms ease,
164
+ overlay 120ms allow-discrete,
165
+ display 120ms allow-discrete;
166
+ }
167
+
168
+ .fs-select[data-picker="styled"]:open::picker(select) {
169
+ opacity: 1;
170
+ }
171
+
172
+ @starting-style {
173
+ .fs-select[data-picker="styled"]:open::picker(select) {
174
+ opacity: 0;
175
+ }
176
+ }
177
+
178
+ /* Høyden kan bare animeres der `calc-size` finnes, siden `auto` ellers
179
+ ikke er en verdi det går an å gå til. Uten støtte står høyden på
180
+ `auto`, og bare gjennomsiktigheten tones. */
181
+ @supports (block-size: calc-size(auto, size)) {
182
+ .fs-select[data-picker="styled"]::picker(select) {
183
+ block-size: 0;
184
+ transition:
185
+ opacity 120ms ease,
186
+ block-size 120ms ease,
187
+ overlay 120ms allow-discrete,
188
+ display 120ms allow-discrete;
189
+ }
190
+
191
+ .fs-select[data-picker="styled"]:open::picker(select) {
192
+ block-size: calc-size(auto, size);
193
+ }
194
+
195
+ @starting-style {
196
+ .fs-select[data-picker="styled"]:open::picker(select) {
197
+ block-size: 0;
198
+ }
199
+ }
200
+ }
201
+
202
+ /* Gruppeoverskriften er ikke et element vi kan treffe når den kommer fra
203
+ `label=`, bare fra `<legend>`. Derfor settes den på gruppa, og arves
204
+ ned: størrelsen og fargen skiller den fra valgene, og `text-indent`
205
+ gir den samme venstrekant som teksten i et valg. Valgene setter de tre
206
+ tilbake til sine egne verdier. */
207
+ .fs-select[data-picker="styled"] optgroup {
208
+ padding-block: var(--size-2) var(--size-1);
209
+ font-size: var(--font-size-s);
210
+ color: var(--semantic-muted-foreground);
211
+ text-indent: var(--size-3);
212
+ }
213
+
214
+ .fs-select[data-picker="styled"] option {
215
+ text-indent: 0;
216
+ display: flex;
217
+ align-items: center;
218
+ gap: var(--size-2);
219
+ padding: var(--fs-select-option-padding, var(--size-2) var(--size-3));
220
+ font-family: inherit;
221
+ font-size: var(--font-size-m);
222
+ line-height: 1.5;
223
+ color: var(--semantic-page-foreground);
224
+ background: var(--semantic-page-background);
225
+ cursor: pointer;
226
+ }
227
+
228
+ /* Haken står etter teksten, ikke foran den, slik at alle valgene får
229
+ teksten på samme sted. */
230
+ .fs-select[data-picker="styled"] option::checkmark {
231
+ order: 1;
232
+ margin-inline-start: auto;
233
+ }
234
+
235
+ .fs-select[data-picker="styled"] option:hover {
236
+ background: var(--semantic-interactive-background);
237
+ }
238
+
239
+ .fs-select[data-picker="styled"] option:checked {
240
+ background: var(--semantic-interactive-main);
241
+ color: var(--semantic-interactive-contrast);
242
+ }
243
+
244
+ /* Fokus vises med en ramme, ikke med en flate. Piltastene flytter fokus
245
+ mellom valgene, og det valgte har allerede sin egen flate. En annen
246
+ bakgrunnsfarge ville derfor forsvunnet nettopp der brukeren står. */
247
+ .fs-select[data-picker="styled"] option:focus {
248
+ outline: 2px solid var(--semantic-interactive-main);
249
+ outline-offset: -2px;
250
+ }
251
+
252
+ .fs-select[data-picker="styled"] option:checked:focus {
253
+ outline-color: var(--semantic-interactive-contrast);
254
+ }
255
+
256
+ .fs-select[data-picker="styled"] option:disabled {
257
+ color: var(--semantic-disabled-foreground);
258
+ background: var(--semantic-disabled-background);
259
+ cursor: not-allowed;
260
+ }
261
+
262
+ @media (prefers-reduced-motion: reduce) {
263
+ .fs-select[data-picker="styled"]::picker(select),
264
+ .fs-select[data-picker="styled"]::picker-icon {
265
+ transition: none;
266
+ }
267
+ }
268
+ }
269
+
86
270
  /* Høykontrast: pilen er to gradienter, og de fjernes i modusen. Da er
87
- nettleserens egen pil bedre enn ingen. */
271
+ nettleserens egen pil bedre enn ingen. Lista som tegnes i siden
272
+ faller tilbake av samme grunn: nettleserens egen liste bruker systemfargene, og de er
273
+ de eneste som er garantert lesbare i modusen. */
88
274
  @media (forced-colors: active) {
89
- .fs-select {
275
+ .fs-select,
276
+ .fs-select[data-picker="styled"] {
277
+ display: block;
90
278
  appearance: auto;
91
279
  background-image: none;
92
- padding-inline-end: var(--size-3);
280
+ padding-inline: var(--size-3);
93
281
  }
94
282
  }
95
283
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  attributes,
3
+ createGuard,
3
4
  type FieldState,
4
5
  fieldStates,
5
6
  isFieldState,
@@ -8,14 +9,29 @@ import {
8
9
 
9
10
  export const SELECT_CLASS = "fs-select" as const
10
11
 
12
+ /**
13
+ * Hvem som tegner nedtrekkslista.
14
+ *
15
+ * `auto` er nettleserens egen liste, et vindu fra operativsystemet som ikke
16
+ * kan styles. `styled` ber nettleseren tegne den inne i siden i stedet, slik
17
+ * at den får designsystemets farger, avstander og skygge.
18
+ */
19
+ export const selectPickers = ["auto", "styled"] as const
20
+ export type SelectPicker = (typeof selectPickers)[number]
21
+ export type NonDefaultSelectPicker = Exclude<SelectPicker, "auto">
22
+ export const isSelectPicker = createGuard(selectPickers)
23
+
11
24
  export type SelectOptions = {
12
25
  /** Valideringstilstand. Standard: `default`. */
13
26
  state?: FieldState
27
+ /** Hvem som tegner nedtrekkslista. Standard: `auto`. */
28
+ picker?: SelectPicker
14
29
  }
15
30
 
16
31
  export type SelectAttributes = {
17
32
  class: typeof SELECT_CLASS
18
33
  "data-state"?: NonDefaultFieldState
34
+ "data-picker"?: NonDefaultSelectPicker
19
35
  "aria-invalid"?: "true"
20
36
  }
21
37
 
@@ -24,17 +40,24 @@ export type SelectAttributes = {
24
40
  *
25
41
  * ```ts
26
42
  * <select {...select({ state: "invalid" })} />
43
+ * <select {...select({ picker: "styled" })} />
27
44
  * ```
28
45
  */
29
46
  export const select = Object.assign(
30
- ({ state = "default" }: SelectOptions = {}): SelectAttributes =>
47
+ ({
48
+ state = "default",
49
+ picker = "auto",
50
+ }: SelectOptions = {}): SelectAttributes =>
31
51
  attributes({
32
52
  class: SELECT_CLASS,
33
53
  "data-state": state === "default" ? undefined : state,
54
+ "data-picker": picker === "auto" ? undefined : picker,
34
55
  "aria-invalid": state === "invalid" ? ("true" as const) : undefined,
35
56
  }),
36
57
  {
37
58
  states: fieldStates,
38
59
  isState: isFieldState,
60
+ pickers: selectPickers,
61
+ isPicker: isSelectPicker,
39
62
  },
40
63
  )
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  import {
2
3
  CONNECTION_STATUS_BAR_CLASS,
3
4
  CONNECTION_STATUS_CLASS,
@@ -36,7 +37,7 @@ const KVITTERING_MS = 4000
36
37
  * }
37
38
  * ```
38
39
  */
39
- export class FsConnectionStatus extends HTMLElement {
40
+ export class FsConnectionStatus extends HostElement {
40
41
  static observedAttributes = ["offline-text", "online-text"]
41
42
 
42
43
  private bar?: HTMLElement
@@ -138,7 +139,5 @@ declare global {
138
139
  export function defineFsConnectionStatus(
139
140
  tagName = FS_CONNECTION_STATUS_TAG,
140
141
  ): void {
141
- if (!customElements.get(tagName)) {
142
- customElements.define(tagName, FsConnectionStatus)
143
- }
142
+ defineElement(tagName, FsConnectionStatus)
144
143
  }
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  import {
2
3
  SESSION_TIMEOUT_CLASS,
3
4
  SESSION_TIMEOUT_DIALOG_CLASS,
@@ -47,7 +48,7 @@ function ord(sekunder: number): string {
47
48
  * .addEventListener("session-extend", () => fetch("/forleng", { method: "POST" }))
48
49
  * ```
49
50
  */
50
- export class FsSessionTimeout extends HTMLElement {
51
+ export class FsSessionTimeout extends HostElement {
51
52
  static observedAttributes = ["warn-at", "expires-at"]
52
53
 
53
54
  private dialog?: HTMLDialogElement
@@ -210,7 +211,5 @@ declare global {
210
211
  }
211
212
 
212
213
  export function defineFsSessionTimeout(tagName = FS_SESSION_TIMEOUT_TAG): void {
213
- if (!customElements.get(tagName)) {
214
- customElements.define(tagName, FsSessionTimeout)
215
- }
214
+ defineElement(tagName, FsSessionTimeout)
216
215
  }
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  import { TOAST_CLASS, TOAST_CLOSE_CLASS } from "./toast.js"
2
3
 
3
4
  export const FS_TOAST_TAG = "fs-toast" as const
@@ -43,7 +44,7 @@ export type ShowOptions = {
43
44
  * })
44
45
  * ```
45
46
  */
46
- export class FsToast extends HTMLElement {
47
+ export class FsToast extends HostElement {
47
48
  static observedAttributes = ["duration", "label"]
48
49
 
49
50
  /** Standard levetid i millisekunder. `0` lar meldingene bli stående. */
@@ -149,7 +150,5 @@ declare global {
149
150
  }
150
151
 
151
152
  export function defineFsToast(tagName = FS_TOAST_TAG): void {
152
- if (!customElements.get(tagName)) {
153
- customElements.define(tagName, FsToast)
154
- }
153
+ defineElement(tagName, FsToast)
155
154
  }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Grunnlaget web-komponentene arver fra, og registreringen av dem.
3
+ *
4
+ * `HTMLElement` og `customElements` finnes bare i nettleseren. En
5
+ * `class X extends HTMLElement` blir evaluert i det modulen lastes, så en
6
+ * server som bare ville hente `fs.button()` fra pakken stoppet med
7
+ * «HTMLElement is not defined» før den kom så langt. Det rammet ni av
8
+ * inngangspunktene, hovedinngangen inkludert, og gjorde pakken ubrukelig i
9
+ * nettopp den situasjonen den er bygd for: at serveren skriver markupen.
10
+ *
11
+ * Reserven er en tom klasse. Den blir aldri brukt til noe, for uten
12
+ * `customElements` blir ingenting registrert, og uten registrering lager
13
+ * nettleseren aldri en forekomst. Den finnes bare for at modulen skal kunne
14
+ * lastes.
15
+ */
16
+ export const HostElement =
17
+ typeof HTMLElement === "undefined"
18
+ ? (class {} as unknown as typeof HTMLElement)
19
+ : HTMLElement
20
+
21
+ /**
22
+ * Registrerer et egendefinert element, én gang, og bare i nettleseren.
23
+ *
24
+ * Kalles `defineFs*` fra en modul som også kjøres på serveren, som i
25
+ * TanStack Start eller en React-app med server-rendring, skal det ikke skje
26
+ * noe. Der finnes det ingen `customElements` å registrere i.
27
+ */
28
+ export function defineElement(
29
+ tagName: string,
30
+ element: CustomElementConstructor,
31
+ ): void {
32
+ if (typeof customElements === "undefined") return
33
+ if (!customElements.get(tagName)) customElements.define(tagName, element)
34
+ }
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  export const FS_ERROR_SUMMARY_TAG = "fs-error-summary" as const
2
3
 
3
4
  /**
@@ -24,7 +25,7 @@ export const FS_ERROR_SUMMARY_TAG = "fs-error-summary" as const
24
25
  * </fs-error-summary>
25
26
  * ```
26
27
  */
27
- export class FsErrorSummary extends HTMLElement {
28
+ export class FsErrorSummary extends HostElement {
28
29
  static observedAttributes = ["autofocus", "hidden"]
29
30
 
30
31
  private hasFocused = false
@@ -77,9 +78,19 @@ export class FsErrorSummary extends HTMLElement {
77
78
  this.links.add(link)
78
79
  }
79
80
 
80
- // Boksen er skjult av serveren når lista er tom. Er den synlig nå, og vi
81
- // ikke har flyttet fokus hit ennå, er det denne innsendingen som feilet.
82
- if (this.shouldFocus && !this.hasFocused && !this.hidden) {
81
+ // Skjuler serveren boksen igjen, er den innsendingen over. Uten denne
82
+ // nullstillingen tok boksen fokus bare første gang: mønsteret i en
83
+ // Datastar-app er at lista står med de samme lenkene hele veien og bare
84
+ // `hidden` slås av og på, så «har jeg flyttet fokus hit før» er ikke et
85
+ // svar på om dette er en ny innsending.
86
+ if (this.hidden) {
87
+ this.hasFocused = false
88
+ return
89
+ }
90
+
91
+ // Er boksen synlig nå, og vi ikke har flyttet fokus hit ennå, er det
92
+ // denne innsendingen som feilet.
93
+ if (this.shouldFocus && !this.hasFocused) {
83
94
  this.hasFocused = true
84
95
  this.focus()
85
96
  }
@@ -134,7 +145,5 @@ declare global {
134
145
  }
135
146
 
136
147
  export function defineFsErrorSummary(tagName = FS_ERROR_SUMMARY_TAG): void {
137
- if (!customElements.get(tagName)) {
138
- customElements.define(tagName, FsErrorSummary)
139
- }
148
+ defineElement(tagName, FsErrorSummary)
140
149
  }
@@ -152,19 +152,28 @@ export function computeFieldAttributes(
152
152
  * lister på de to andre forsvinner klassen og feilmeldingen ved neste
153
153
  * morfing, som er nøyaktig den feilen kontrakten skal hindre.
154
154
  *
155
+ * Hjelpeteksten og feilmeldingen må ha `id` med i lista selv om malen ikke
156
+ * skriver noen. Komponenten lager dem i så fall selv, og `aria-describedby`
157
+ * på kontrollen peker på dem. Forsvinner id-en i en morfing, peker
158
+ * koblingen på noe som ikke finnes, og skjermleseren leser verken
159
+ * hjelpeteksten eller feilen. `for` på ledeteksten er der av samme grunn.
160
+ *
155
161
  * ```html
156
- * <label class="fs-label" for="epost"
157
- * data-preserve-attr="class data-required data-optional aria-disabled">E-post</label>
158
- * <input class="fs-input" id="epost"
162
+ * <label class="fs-label"
163
+ * data-preserve-attr="class for data-required data-optional aria-disabled">E-post</label>
164
+ * <input class="fs-input"
159
165
  * data-preserve-attr="id aria-describedby aria-invalid data-state disabled aria-disabled">
160
- * <p class="fs-error-text" hidden data-preserve-attr="hidden">Skriv en gyldig adresse.</p>
166
+ * <p class="fs-help-text" data-preserve-attr="id">Vi sender aldri spam.</p>
167
+ * <p class="fs-error-text" hidden data-preserve-attr="id hidden">Skriv en gyldig adresse.</p>
161
168
  * ```
162
169
  */
163
170
  export const FIELD_PRESERVED_ATTRIBUTES = {
164
171
  /** På ledeteksten. */
165
- label: "class data-required data-optional aria-disabled",
172
+ label: "class for data-required data-optional aria-disabled",
166
173
  /** På selve kontrollen. */
167
174
  control: "id aria-describedby aria-invalid data-state disabled aria-disabled",
175
+ /** På hjelpeteksten. */
176
+ help: "id",
168
177
  /** På feilmeldingen. */
169
- error: "hidden",
178
+ error: "id hidden",
170
179
  } as const
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  import { computeFieldAttributes } from "./field-core.js"
2
3
 
3
4
  export const FS_FIELD_TAG = "fs-field" as const
@@ -31,7 +32,7 @@ function setOrRemove(
31
32
  * det ved hver patch. Se `FIELD_PRESERVED_ATTRIBUTES` for hva serveren må
32
33
  * skrive for at koblingen skal overleve en morfing.
33
34
  */
34
- export class FsField extends HTMLElement {
35
+ export class FsField extends HostElement {
35
36
  static observedAttributes = [
36
37
  "invalid",
37
38
  "disabled",
@@ -232,7 +233,5 @@ declare global {
232
233
  }
233
234
 
234
235
  export function defineFsField(tagName = FS_FIELD_TAG): void {
235
- if (!customElements.get(tagName)) {
236
- customElements.define(tagName, FsField)
237
- }
236
+ defineElement(tagName, FsField)
238
237
  }
@@ -1,3 +1,4 @@
1
+ import { defineElement, HostElement } from "../../host-element.js"
1
2
  export const FS_POPOVER_TAG = "fs-popover" as const
2
3
 
3
4
  type Placement = "bottom-start" | "bottom-end" | "top-start" | "top-end"
@@ -32,7 +33,7 @@ const PLACEMENTS: readonly Placement[] = [
32
33
  * </fs-popover>
33
34
  * ```
34
35
  */
35
- export class FsPopover extends HTMLElement {
36
+ export class FsPopover extends HostElement {
36
37
  static observedAttributes = ["open", "placement"]
37
38
 
38
39
  private panel?: HTMLElement
@@ -205,7 +206,5 @@ declare global {
205
206
  }
206
207
 
207
208
  export function defineFsPopover(tagName = FS_POPOVER_TAG): void {
208
- if (!customElements.get(tagName)) {
209
- customElements.define(tagName, FsPopover)
210
- }
209
+ defineElement(tagName, FsPopover)
211
210
  }